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. 【08】Jenkins:关于发布

    写在前面的话 Jenkins 对于我们用户而言,可能中间会有不同的需求,比如自动构建,接口测试,代码质量检测.但其实我们的最终目的还是打包上线.当然,各个公司的项目开发语言会不一样,但是总体而言发布方 ...

  2. 2019-11-29-dotnet-通过-WMI-获取指定进程的输入命令行

    原文:2019-11-29-dotnet-通过-WMI-获取指定进程的输入命令行 title author date CreateTime categories dotnet 通过 WMI 获取指定进 ...

  3. [世预赛] 中国vs菲律宾,第一场考验,国足力争三连胜,比分预测:3:0, 2:0,4:1

    7比0大胜关岛,中国国家男子足球队在冲击2022卡塔尔世界杯的征途上收获两连胜,北京时间10月15日20点,中国男足将奔赴巴科洛德,客场挑战菲律宾男足,本场比赛也是中国男足在本次世预赛四十强赛阶段的第 ...

  4. Asp.net MVC企业级开发(09)---T4模板

    T4即为Text Template Transformation Toolkit,一种可以由自己去自定义规则的代码生成器.根据业务模型可生成任何形式的文本文件或供程序调用的字符串 在VS中T4模板是没 ...

  5. 线程---Day22

    并发与并行 并发:指两个或多个事件在同一个时间段内发生. 并行:指两个或多个事件在同一时刻发生(同时发生) 在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单CPU系 ...

  6. 网页百度地图api,支持位置偏移

    网页百度地图api,支持位置偏移 需加载 jq <style type="text/css"> #allmap {width:100%; height:100%; bo ...

  7. vue+element拖动排序功能

    项目中老大心血来潮设计了一可以拖动达到排序的功能,感觉没什么用,但是没办法,实现吧! 这功能肯定不会手撸了,直接上插件 使用Sortable.js,对vue不友好,拖拽有时候乱跳;改用vuedragg ...

  8. C++ OpenSSL 之五:生成P12文件

    1.等同于使用: openssl pkcs12 -export -inkey "key_path" -in "pem_path" -out "save ...

  9. ECharts将折线变平滑和去掉点的属性(转载)曲线变圆滑

    本文链接:https://blog.csdn.net/sinat_36422236/article/details/62430114 series : [ { name:'your name', sy ...

  10. 集成学习-Majority Voting

    认识 集成学习(Ensemble Methods), 首先是一种思想, 而非某种模型, 是一种 "群体决策" 的思想, 即对某一特定问题, 用多个模型来进行训练. 像常见的单个模型 ...