在公司负责服务端 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 默认不会去修改,执行完就会去恢复,使用的是序列化和反序列化
虽然看不懂,但学是给个赞吧~