在公司负责服务端 Api 开发,为安卓客户端提供相应的接口,在开发的过程中,免不了要测试完成的接口是否可用。最开始的测试手段是使用 POSTMAN 等工具发送请求。使用这类工具的流程一般是,先构造 url 请求接口进行登录,登录后拿到服务器返回的一个标识(可以看做是一个 session,但这个 session 的概念和传统的网站开发中的 session 概念不一样),在后续的接口调用中,都需要在请求 header 头里面加上那个标识。这个流程会比较繁琐,至少需要多次鼠标点击以及复制粘贴的过程才能完成。偶尔这样做还好,这种事情做多了便让我觉得烦躁无比。
了解了下 PHPUnit,先读了读官网的 manual,大体明白怎么写测试了就开始动手。
具体到我们的业务,首先写了一个 Client 类,这个类主要作用是模仿客户端发一个请求,当然这个类会进行一些简单的封装,比如 curl 请求的时候带上我们的标识(上文说的 session),还有其它的模拟安卓客户端的一些请求头。刚开始我在每个测试方法中都 new 一个 Client 对象,后来想想不对,既然是模仿客户端,而一个客户端永远是一个实例,每次 new 一个出来显然不符合现实逻辑,另外一个问题是,测试登录接口后,session 标识需要在后续的接口测试中反复使用。想到这,于是将 Client 类改为了单例实现,这样就能保证在多个测试方法的 Client 为同一个实例对象,并能共享 session 标识状态。
下面是 Client 的实现及一个简单的测试用例文件示例:
class Client { private function __construct() { } private static $instance; public $session; public function getInstance() { if (is_null(static::$instance)) { static::$instance = new static(); } return static::$instance; } public function curl($url) { $ch = curl_init(); if (!is_null($this->session)) { // 如果 session 不为空,则在 curl 请求时加上保存 session 信息的 header 头 } // 使用 curl 发送请求 $response = curl_exec($ch); return $response; } } class Test extends PHPUnit_Framework_TestCase { public function testLogin() { $client = Client::getInstance(); $response = $client->curl($login_url); // 下面就可以进行一些 assert 啦 // 登录成功后设置 session 为服务器返回的 session $client->session = $session_get_from_response; } /** * @depends testLogin */ public function testGetUserInfo() { $client = Client::getInstance(); $response = $client->curl($get_user_info_url); // 接下来的代码进行后续处理 } }
要测试新的接口,只需要增加新的方法就好了,多次测试多次运行单元测试命令就 OK 了,可以节约大量时间啊。
另外,我发现在单元测试类里面的不同方法好像是单独运行的,比如下面的这个代码:
class Test2 extends PHPUnit_Framework_TestCase { public function testOne() { $GLOBALS['count'] += 1; echo $GLOBALS['count']; } public function testTwo() { $GLOBALS['count'] += 2; echo $GLOBALS['count']; } }
输出结果为 1 2 ,并不是想象中的 1 3,这是为什么呢?
global 全局变量,PHPUnit 默认不会去修改,执行完就会去恢复,使用的是序列化和反序列化
虽然看不懂,但学是给个赞吧~