文档章节

进阶篇:如何为ThinkPHP5编写优质的单元测试?

暗夜在火星
 暗夜在火星
发布于 05/08 15:50
字数 1228
阅读 122
收藏 2

前言

在项目开发中,需要使用到ThinkPHP 5,为了编写单元测试,解决了几个难题,特此纪录分享一下。

 

难点1:TP5自带的单元测试感觉不好用,如何使用纯粹的原生PHPUnit?

在看云上,有TP5官方关于单元测试的使用说明,链接是:https://www.kancloud.cn/manual/thinkphp5/182511

但上面的说明过于简单,对于实际使用帮助有限。

 

对于一直钟情于自动化单元测试以及PHPUnit原生单元测试的我,决定对此优化一番,引入并在ThinkPHP 5下使用原生PHPUnit。

第一步:准备工作

在tests目录下,创建一个phpunit目录,然后创建两个文件:测试启动文件bootstrap.php和单元测试的配置文件phpunit.xml。

测试启动文件bootstrap.php,可以参考项目的启动文件,复制过来后调整下,例如这样:

<?php
// 定义应用目录
define('APP_PATH', __DIR__ . '/../../application/');

define('APP_DEBUG', true);     //开启调试模式
define("APP_STATUS", "tests"); //定义为本地环境
define("RUNTIME_PATH", __DIR__ . "/../../runtime/"); //定义缓存目录

require APP_PATH . '/define.php';

// ThinkPHP 引导文件
// 加载基础文件
require __DIR__ . '/../../thinkphp/base.php';

// 加载应用
\think\Loader::addNamespace('app', APP_PATH);

// 兼容旧版本的PHPUnit
if (!class_exists('PHPUnit_Framework_TestCase')) {
    class PHPUnit_Framework_TestCase extends PHPUnit\FrameWork\TestCase {
    }
}

// 手动再引入一次测试配置
\think\Config::load(APP_PATH . '/tests/test.php');

// 手动引入框架和应用的函数
require_once APP_PATH . '../thinkphp/helper.php';
require_once APP_PATH . 'common.php';

对于phpunit.xml配置文件,可以这样写:

<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
    backupStaticAttributes="false"
    colors="true"
    bootstrap="./bootstrap.php"
    convertErrorsToExceptions="true"
    convertNoticesToExceptions="true"
    convertWarningsToExceptions="true"
    processIsolation="false"
    stopOnFailure="false"
    syntaxCheck="false"
    >
    <php>
        <ini name="intl.default_locale" value="en"/>
        <ini name="intl.error_level" value="0"/>
        <ini name="memory_limit" value="-1"/>
    </php>

    <testsuites>
        <testsuite name="Test Suite">
            <directory suffix="Test.php">./</directory>
            <directory suffix="Test.php">./application</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">../../application</directory>
        </whitelist>
    </filter>
</phpunit>

第二步:写个简单的demo

下面编写一个简单的测试用例,试运行一下。在phpunit下创建一个demo目录,并创建TestCaseClass.php文件。此时结构如下:

$ tree ./phpunit 
./phpunit
├── bootstrap.php
├── demo
│   └── TestCaseClass.php
└── phpunit.xml

TestCaseClass.php文件代码是:

<?php
use PHPUnit\Framework\TestCase;

namespace tests\demo;

class TestCaseClass extends \PHPUnit_Framework_TestCase
{
    public function testHere()
    {
        $this->assertTrue(true);
    }
}

这样编写成功后,就可以试运行了。

第三步:运行一个简单的PHPUnit测试

$ phpunit ./demo/TestCaseClass.php    
PHPUnit 5.7.25 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 121 ms, Memory: 10.00MB

OK (1 test, 1 assertion)

后面就可以继续这样编写原生的PHPUnit单元测试啦。

 

难点2:如何使用PhalApi开源框架的脚本,为TP5项目自动生成测试代码?

下面就要为TP5的项目代码编写单元测试了,但每次都要人工手动重复编写测试代码是一件很累人、很耗时、很低率的工作。有没更好的技能?有!

参考我曾经编写的脚本工具:[PHPUnit]自动生成PHPUnit测试骨架脚本-提供您的开发效率【2015升级版】

现在已经成为PhalApi开源框架内置的脚本命令了。PhalApi是一个专注于接口开发的开源框架,因此我们可以把PhalApi的phalapi-buildtest脚本命令整合到ThinkPHP 5 的项目里,

 

非常重要的链接

使用说明和详细的官方文档:PhalApi 2.x 单元测试

脚本命令Github下载地址(需要同时下载这两个文件):

https://github.com/phalapi/phalapi/blob/master-2x/bin/phalapi-buildtest

https://github.com/phalapi/phalapi/blob/master-2x/bin/build_test.php

 

下载后放到tests/phpunit目录下,此时文件结构如下:

$ tree ./phpunit 
./phpunit
├── bootstrap.php
├── build_test.php
├── demo
│   └── TestCaseClass.php
├── phalapi-buildtest
└── phpunit.xml

 

准备好后,就可以开始生成单元测试的代码啦!

例如,可执行:

$ ./phalapi-buildtest ../../application/controller/Site.php 'app\controller\Site' > ./controller/SiteTest.php

生成后,便可执行。

 

难点3:如何测试controller,以及如何解决input()的参数缓存?

正常情况下,进行单个单元测试时,以下测试代码是可以的:

    public function testLogin()
    {
        $_POST['email'] = 'phpunit123';
        $_POST['password'] = '123456';
        $_POST['remember'] = '1';

        $rs = $this->appcontrollerSite->login();

        $this->assertEquals(1, $rs['code']);
    }

对应的源代码是:

<?php

class Site extends Controller {

    public function login() {
        $username = input('post.email');
        $password = input('post.password');
        $remember = input('post.remember/d', 0);

        // todo
    }
}

但是,如果执行全部单元测试的话,传给controller的$_POST参数就失效了。这是因为ThinkPHP5的Request是一个单例,并且在think\Request::$post变量中缓存了POST参数,导致后面的参数不生效。

为此,需要这样调整传递参数:

    public function testLogin()
    {
        $_POST['email'] = 'phpunit123';
        $_POST['password'] = '123456';
        $_POST['remember'] = '1';

        // 加多这两行,重置POST参数
        $params = ['POST' => $_POST];
        \think\Request::create('/', 'POST', $params);

        $rs = $this->appcontrollerSite->login();

        $this->assertEquals(1, $rs['code']);
    }

参考

发现了一篇写得很赞的文章:PHPUnit简介及使用(thinkphp5的单元测试安装及使用)

© 著作权归作者所有

暗夜在火星

暗夜在火星

粉丝 169
博文 177
码字总数 326789
作品 1
广州
程序员
私信 提问
「ThinkPHP开发者周刊」第8期——模型和关联

[ 本周读数 ] ——ThinkPHP官方公众号关注数 截至目前为止,ThinkPHP官方公众号(@thinkphp2012)用户订阅数超过(均为自然增长)。由于之前一直缺乏有效的运营而增长缓慢,现每周都会推送最...

流年
2018/11/26
138
0
PHP教程:PHPUnit学习笔记(二)PHPUnit基本用法

上篇日记中我介绍了phpunit的配置方法,今天就开始介绍如何用PHPUnit来编写测试用例,下面我来引入一个测试PHP数组操作的测试用例,这个例子会给你展示PHPUnit常规的用法和测试用例编写的步骤...

peasant
2014/11/07
45
0
4 个 useState Hook 示例

作者:Dave Ceddia 译者:前端小智 来源:daveceddia 为了保证的可读性,本文采用意译而非直译。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 到 React 16.8 目前为止,...

前端小智
08/21
0
0
2018职业测试必读书单

测试基础 软件测试(原书第2版) 全面系统地介绍了软件测试理论及应用技术,不仅讲述基本的测试技能,也讲述成为一个成功的软件测试员所必须掌握的技能。 软件测试的艺术(第3版) 从软件测试...

honzhang
2017/12/22
0
0
前端进阶之路: 前端架构设计(3) - 测试核心

可能很多人和我一样, 首次听到"前端架构"这个词, 第一反应是: "前端还有架构这一说呢?" 在后端开发领域, 系统规划和可扩展性非常关键, 因此架构师备受重视, 早在开发工作启动之前, 他们就被邀...

Lee_tanghui
2017/12/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

IntelliJ IDEA远程连接tomcat,实现单步调试

web项目部署到tomcat上之后,有时需要打断点单步调试,如果用的是Intellij idea,可以通过如下方法实现: 开启debug端口,启动tomcat 以tomcat7.0.75为例,打开bin目录下的catalina.bat文件,...

程序员欣宸
47分钟前
5
0
如何在 Bash 中对变量递增或者递减

导读 编写 Bash 脚本时最常见的算术运算之一是递增和递减变量。这通常在循环中用作计数器,但它也可以在脚本的其他地方出现。 递增和递减意味着分别从数值变量的值中添加或减去值(通常为 1 ...

问题终结者
51分钟前
3
0
如何使用ssh工具便于远程管理

前几天亲眼经历了Linux服务器运维过程,眼看着别人熟练运用Linux管理工具,自个心里不是滋味,所以自己特意整理了一篇“专题”:使用ssh服务远程管理主机。 首先在使用ssh服务工具之前,先熟...

Linux就该这么学
今天
6
0
IT兄弟连 HTML5教程 介绍HTML5给你认识 习题

1.关于HTML5说法正确的是:(C) A.HTML5只是对HTML4的一个简单升级 B.所有主流浏览器都支持HTML5 C.HTML5新增了离线缓存机制 D.HTML5主要是针对移动端进行了优化 2.为了标识一个HTML文...

老码农的一亩三分地
今天
6
0
关于1加手机rom的分析过程

1、关于清理app缓存的信息 framework.jar和services.jar文件,都位于/system/framework目录下面 framework.jar的android.os.Intent类里面定义了action "android.intent.action.CLEAR_PKG",这......

shatian
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部