Laravel 5.1单元测试(PHPUnit)入门

v1.0

作者:ZBW、ZGJ

简介

PHP应用大多应用的单元测试框架是PHPUnit,这一框架也被Laravel集成了进来,并且Laravel增添了一些额外的功能以方便开发者进行Web相关的测试。本文将以项目中应用的单元测试为基础,介绍Laravel下PHPUnit的相关内容。

注意到本文以Laravel 5.1为基础,可能部分API在后续版本中有变动,但整体的使用方法变动不大。

安装与配置

1. 安装

通过composer配置composer.json中的依赖,并使用composer install来安装phpunit,安装后的二进制文件在/vendor/bin/下。

(也可尝试使用apt install phpunit来安装phpunit)

2. 配置

Laravel默认自带了名为phpunit.xml的配置文件,该文件已经为我们配置好了phpunit本身。

项目使用的配置文件如下:

   <?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="bootstrap/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">app/</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
<logging>
<log type="coverage-html" target="./tests/codeCoverage" charset="UTF-8"/>
</logging>
</phpunit>

其中需要注意以下内容:

  • <testsuites>/<directory>:这里存放了测试php代码

  • <logging>:这里设置输出测试结果的位置,输出的内容是html版的覆盖率报告,该报告非常详细。

  • <filter>:该部分定义了phpunit可访问的路径,以上配置中我们只测试app文件夹下的内容。

    基于以上内容,一个方便浏览测试报告的方式是,将tests/codeCoverage文件夹下的报告入口html文档软链接至public文件夹下,从而可以由浏览器直接访问:

   ln -s tests/codeCoverage public/tests

从而浏览器访问路由:/tests即可看到测试报告。

编写测试样例

1. 新建测试样例

规范的方法是使用artisan新建测试样例:

php artisan make:test xxxTest

该命令会在tests文件夹下新建一个xxxTest.php,其中包含了一个默认测试函数。

2. 编写函数的测试

在这部分内容中我们主要需要应用断言来检查函数的输入和输出是否匹配。断言是phpunit本身就带有的功能。

常用的一些断言包括:

$this->assertTrue(表达式) //检查表达式是否为真
$this->assertFalse(表达式) //检查表达式是否为假
$this->assertEquals(X,Y) //检查两个变量是否相等
$this->assertFileExists(文件) //检查文件是否存在

具体的断言函数可参考PHPUnit文档

3. 编写Web功能测试

Laravel集成PHPUnit最方便的地方是其可以编写关于Web控制器及功能的测试。

例如测试某个页面访问是否正常的测试内容如下:

    public function testIndex()
{
$this->visit('logout') ;
$this->visit('/desexp')
->see("设计性实验")
->see("请选择实验")
->see("D01"); $this->visit('/login')
->see('登录')
->type($this->gen_admin_email , 'email')
->type($this->gen_admin_password , 'password')
->press('login-submit'); $this->visit('/desexp')
->see("设计性实验")
->see("请选择实验")
->see("D01");
}

这部分测试编写的方式是将所有需要运行的函数按先后顺序串联起来。

3.1 测试页面访问

一些访问方面的函数如下,这部分函数一般用于测试访问及与页面进行交互。

visit('路由') // 访问某个地址
see('xxx') //检查访问的页面中是否出现了xxx
dontSee('xxx') //与see功能相反,检查是否没有出现xxx
type('输入内容',输入框name属性) //输入内容至输入框
check('单选框name属性') //选中checkbox
select(’内容‘,’下拉菜单区域‘) //选择下拉菜单项
press('xxx') //按下指定元素或按钮
attach('文件路径','文件上传name属性') //附加文件

在上文的例子中,我们测试前可以选择手动模拟登陆操作。

3.2 测试JSON API

测试JSON API时以上的函数往往起不到作用,此时需要使用如下的函数来向接口发起请求及验证结果。

get/post/put/patch/delete('address',[payloads]) //以以上的HTTP方法请求路由
seeJson([json内容]) //检查返回的json是否包含内容

当然之前的visit方法可以看作没有额外数据的get(注意不是无参数,后文会介绍)

一个例子如下,这部分代码通过getTable函数验证了获取html表格内容的正确性。

        $_GET['id'] = $this->report_id_pub ;
$html_file = Config::get('phylab.experimentViewPath').$this->report_id_pub.".html";
$str_html = file_get_contents($html_file);
$this->visit('/getTable')
->seeJson([
'status' => SUCCESS_MESSAGE ,
'contents' => $str_html ,
]) ;

此外,还有call('http请求方法','路由',‘数据’...)这一方法以更灵活的方式向接口发起请求。这一函数将返回Laravel原生的http请求对象。你可以继而通过phpunit的断言验证其中结果。

Laravel增加了一些额外的断言以方便用户检查Web请求的结果。例如:

->assertResponseOk(); //检查返回是否为HTTP 200
->assertResponseStatus($code); //检查返回是否是指定的状态码
->assertRedirectedTo($uri, $with = []); //检查是否有重定向

具体可以参考[PHPUnit Assertions]([https://laravel.com/docs/5.1/testing#PHPUnit Assertions](https://laravel.com/docs/5.1/testing#PHPUnit Assertions))

3.3 一些问题

1. 中间件

在Laravel中部分路由通过中间件来确保安全性,例如很多API以Auth中间件来确保只有登陆用户才能使用接口,但在测试中经常登陆无疑增加了测试的复杂性,使用session相对来说也是一种麻烦的办法。

可以在测试类的开头增加如下内容

use WithoutMiddleware;

从而在该测试代码文件中暂时使中间件不产生作用

2. 数据库

部分测试的函数需要对数据库进行操作,而测试前后需要保证数据库状态的一致性。手动进行恢复的操作也不现实,好在Laravel内置了一些方法使我们能方便地进行数据库方面的测试

使用迁移:use DatabaseMigrations; 或使用事务:use DatabaseTransactions;

将以上内容任一个添加在测试类开头,Laravel会替你完成数据库在测试前后的恢复工作

3. 关于define的问题

在我们的项目中,之前的开发者在很多地方定义了一些全局变量,或者可以说是类似于C语言的宏定义。包括Laravel框架本身中也包含了很多这样的宏定义。初次运行测试时我们遇到的一个很尴尬的问题是:不能有多个测试代码文件,否则phpunit就会报类似于”重复定义“的错误。

一个暂时的解决办法是这样的,在每个测试类开头添加:

    protected $preserveGlobalState = FALSE;
protected $runTestInSeparateProcess = TRUE;

这两者意味着每个测试进程是独立的,且各测试之间的状态不被保留。

4. 关于HTTP请求的参数和载荷

前述的一些用于测试的请求方法,其中可以额外附带的数组参数实际上是请求附带的payloads,但很多时候我们要发起类似这样的带参数请求:

http://ip:port/getTable?id=1234567

如果直接在get方法内设置['id'=>'1234567'],会发现测试运行中还是直接请求/getTable,而没有任何参数

一个解决办法是测试时直接修改PHP的_GET变量,例如

$_GET['id'] = '1234567' ;

这一办法笔者认为有些简单粗暴,但还没找到更好的方法,还请各位读者多多指教。

运行测试与查看结果

1. 运行测试

运行测试非常简单,只需要在phpunit.xml所在的目录下运行:phpunit,即可自动运行所有测试。

如果你想运行单个测试文件,可以以如下方式:

phpunit path\to\testFile.php

这将运行该文件中的所有测试函数。

你也可以运行某一个测试函数,但该情况下最好指定该函数所在的文件,以避免重名的情况:

phpunit --filter testFunction path\to\testFile.php

2. 查看结果

在配置部分配置了软链接后,你可以直接进入测试报告的页面

ln -s tests/codeCoverage public/tests

直接访问ip:port/tests后将自动进入测试报告的主页,点击每个文件夹可以浏览其中内容的测试覆盖率。

测试覆盖率分为三栏,第一栏是覆盖的行数,第二栏是方法数,第三栏是覆盖的类的数量。

【技术博客】 Laravel 5.1单元测试(PHPUnit)入门的更多相关文章

  1. 个人作业——软件工程实践总结&个人技术博客

    一. 回望 (1)对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强软件工程专业的能力和就业竞争力",对比目前的所学所练所得,在哪些方面达到了你的期待和目标,哪些方面还存在哪 ...

  2. 如何写出高质量的技术博客 这边文章出自http://www.jianshu.com/p/ae9ab21a5730 觉得不错直接拿过来了 好东西要大家分享嘛

        如何写出高质量的技术博客?答案是:如果你想,就一定能写出高质量的技术博客.看起来很唯心,但这就是事实.有足够愿力去做一件目标明确,有良好反馈系统的事情往往很简单.就是不停地训练,慢慢地,你自己 ...

  3. ******IT公司面试题汇总+优秀技术博客汇总

    滴滴面试题:滴滴打车数据库如何拆分 前端时间去滴滴面试,有一道题目是这样的,滴滴每天有100万的订单,如果让你去设计数据库,你会怎么去设计? 当时我的想法是根据用户id的最后一位对某个特殊的值取%操作 ...

  4. 转: BAT等研发团队的技术博客

    BAT 技术团队博客   1. 美团技术团队博客:  地址: http://tech.meituan.com/ 2. 腾讯社交用户体验设计(ISUX) 地址:http://isux.tencent.c ...

  5. 解决Eclipse中文乱码 - 技术博客 - 51CTO技术博客 http://hsj69106.blog.51cto.com/1017401/595598/

    解决Eclipse中文乱码 - 技术博客 - 51CTO技术博客  http://hsj69106.blog.51cto.com/1017401/595598/

  6. 欢迎访问我的最新个人技术博客http://zhangxuefei.top

    博客园已停止更新,欢迎访问我的最新个人技术博客http://zhangxuefei.top

  7. 技术博客(初用markdown)。

    技术博客 菜鸟教程在这个网站我学到许多有趣的东西,并且弥补了我之前的一些不足之处. 以下为我学习到的内容 输出不同的三位数 以下为代码和输出结果 *** #include<stdio.h> ...

  8. 技术博客(初用markdown)

    技术博客 菜鸟教程在这个网站我学到许多有趣的东西,并且弥补了我之前的一些不足之处. 以下为我学习到的内容. 1 如果想输出多个多位数的时候,可以尝试用多个if语句.如果需要输出3为数的时候,设置三个变 ...

  9. 【转】【技术博客】Spark性能优化指南——高级篇

    http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...

  10. 作业一:创建个人技术博客、自我介绍、简单的C程序

    年9月14日中午12点: 一.主要内容  建个人技术博客(博客园 www.cnblogs.com) 本学期将通过写博客的方式提交作业,实际上,最终的目的是希望同学们能通过博客的形式记录我们整个学习过程 ...

随机推荐

  1. 我得新博客上线了采用Vue+Layui的结合开发,后台采用asp.net mvc

    地址:www.zswblog.xyz 写完这个博客项目我真的很开心! 希望博客园的大佬们能去看看,如果可以希望帮我在Layui的年度案例点一个赞,谢谢! 地址:https://fly.layui.co ...

  2. Linux 目录简介

    这里以Centos7为例: 使用tree命令查看/目录结构如下: 下面我们主要探讨如下主要目录: /:根目录不必多说,文件系统的最顶端,存放系统所有目录. bin:该目录主要存放系统运行所需要的重要命 ...

  3. virtualbox通过Nat模式上网,宿主机与宿主机互通

    本地搭建virtualbox,开始用的nat转发模式,这样的话宿主机没法访问虚拟机里面的服务.比如nginx网站.这样很不方便 . 在网上找了好久,终于找到了方案.那就是再添加一块虚拟网卡. 在虚拟机 ...

  4. python神操作将list拉平

    python 神操作   将list 拉平 list_of_lists = [[1], [2, 3], [4, 5, 6]]sum(list_of_lists, [])

  5. 自动居中标题和内容;aspxgridview允许定义两个关键字为主键的格式

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  6. EHLIB 安装方法

    Ehlib安装方法  路人甲 2010-05-05 23:01:37 安装文件自带的Readme.txt中的安装过程如下: 1. Delphi 5.x - 7.x, Delphi 9.X Win32, ...

  7. Robot Framework常用关键字

    虽然通过RIDE提供"填表"一样的写测试用例的方式.但它却支持强大的关键字功能,以及可以开发关键字的扩展能力. Comment 注释功能,也可以使用python中的"#& ...

  8. 【前端_React】Node.js和webpack的安装

    第一步——安装Node.js 首先要安装Node.js,Node.js自带了软件包管理工具npm,可以使用npm安装各种插件.Node.js的下载地址 可以自定义安装到指定的路径下,待安装完成后命令行 ...

  9. 安装Ubuntu后需要做的事

    卸载软件 纸牌 麻将 扫雷 数独 火狐 邮件 扫描 拍照 照片 视频 计划 日历 打印 备份 计算器 亚马逊 电源统计 音乐播放 远程桌面 To Do LibreOffice 换下载源 装机的时候下载 ...

  10. Django中ModelViewSet的应用

    ModelViewSet源码 class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateM ...