单元测试 - 断言

  • 作者:KK

  • 发表日期:2015.12.13


提示:已经了解单元测试知道断言是咋回事的老鸟请直奔下一篇

任何编程的单元测试里会频繁地出现一个词语叫assert,它就是断言的意思,就像刚才的代码$this->assertTrue(返回true/false的表达式或变量/函数)方法一样,它的意思是说我敢断言传进来的值是个true!,就像在说我敢断言他就是凶手!,若一旦他不是凶手,那么结果就是断言失败

一个测试方法里面可以有好多次断言,然而一般情况下只要有其中一次不符合断言的话整个测试方法都会停下来,咱试试下面的代码:

public function testMe(){
	$this->assertTrue(1 + 2 == 3);	//第1次断言,等式成立,断言成功,继续往下运行
	file_put_contents('E:\1.txt', 11);	//不信你看看,这个文件存在喔,说明这里被运行了
	$this->assertTrue(1 + 2 == 4);	//第2次断言,等式不成立,断言失败,下一句将无法运行,运行到这里就会退出这个测试方法,如果有其它测试方法就会再运行另一个测试方法
	file_put_contents('E:\2.txt', 22);	//为了证明不会运行到这里,特设此代码,让你去找找2.txt是否真的不会被创建
	$this->assertTrue(2 + 2 == 4);	//第3次断言,等式成立,但上一句已经断言失败,这里不会被运行

	//最终你就是能看到运行结果提示只运行了2次断言,1次成功1次失败,没有提到第3次断言,因为这个测试方法在第二句断言时就中断了,你也看不到 E:\2.txt 文件的存在
}

上面的代码我在备注里都说明了它的情况,相信你也看懂了,我的意思就是说当一个测试方法里只要有一次断言失败,整个方法就会中断运行不会再往下跑,这是测试的特性,包括未来接触的其它测试也是这样的,至于为什么要有这样的运行规则呢?我觉得不需要解释,你写着写着就会领悟得到


断言的方式

最基本最简单的断言莫过于assertTrue了,比如下面这样的代码:

$this->assertTrue(is_string($name));	//断言名字是字符串来的
$this->assertTrue(is_numerice($age));	//断言年龄是数值来的
$this->assertTrue(is_numerice($age) && $age >= 18);	//并且年龄还是18岁以上
$this->assertTrue($action != '删除');	//断言一个操作标记不会是某个字符
$this->assertTrue(mb_strlen($name) >= 6);	//断言一个名字是至少6个字的
$this->assertTrue($xxx->getYYY() == $qqq->ccc());	//断言两个方法的运行结果应该是相同的
$this->assertTrue(isset($arr['xxx']));	//断言一个数组是有xxx这个下标的

等等,看上去用assertTrue再配合判断表达式,所有测试都能做出来了呀!好了这下先不说这个,先介绍一下别的断言,断言方式其实有好多种,assertTrue只是最基础的,下面列出几个其它断言:

$this->assertEquals(5, count($arr));	//断言一个数组count后的个数是否等于5
$this->assertFalse($user->isLogin());	//断言一个用户对象是未登陆的
$this->assertInstanceOf('app\model\User', $user); //断言一个用户变量是 common\model\User 这个类的实例或子类实例
$this->assertGreaterThan (10, $age);		//断言年龄是大于10岁
$this->assertContains(3, $arr);	//断言数组里是包含了数字3这个值的
$this->assertArrayHasKey('choose_count', $aResult);	//断言一个数组里会有一个叫choose_count的下标

不要老是使用assertTrue

好了,断言的方式有很多,真的很多,结合起一般的测试用例,经常会用到的起码有30多个。加上不常用的估计也有50多

既然有了assertTrue这个几乎万能的断言,为什么还会有那些别的断言呢?--其实是为了提高测试报告的精准性。

按照测试行业的规范,测试用例是不提倡用assertTrue来取代所有断言的,因为测试失败的时候,测试报告就会说"测试不通过,assertTrue失败",这下坑爹了!哪个assertTrue呀?幸好,PHP还报了个行号,打开测试脚本找到那一行就知道是哪个assertTrue了,这个在你能接触代码的时候就好说,在规范化运作里,不可能每次测试完都能去看代码的,比如远程上线的时候,报告说测试失败,可是人不在公司碰不到代码怎么办,而且如果这份代码是测试工程师独有的呢?你能碰得到吗?那么就要靠别的东西来定位

观察下图,这里都是用了assertTrue的断言,它们都是失败的,你能快速定位出它们都是哪里出了问题吗

到下图,用了更精准的方法去断言

那有时候直接看上图就知道testTwo那个断言失败的报错就知道原来类的某个方法返回的数组中没包含orange这样一个值

既然快速定位到了问题所在,接下来你要么哗啦啦地去改相关的类修正返回值,要么去找相关负责人调整这个类,反正不用专门打开测试脚本找到那一行了

测试用例以后都会频繁运行,过程中肯定会因为某个类改了一些代码会断言失败,就需要反复跟进问题,如果总是要打开测试脚本找到那一行才知道具体问题,那么这个工作方式的效率就太低下了。

但其实光是这么说其实也未必能完全精准定位断言的失败位置,只是通常可以这么认为而已,那你看我这个代码

$id = 999;	//实际上可能是什么$db->get('id')的代码赋值得来的嘛
$this->assertTrue(in_array($id, [1, 2, 3]), '无效的ID');	//这里传了第2个参数,一个用于表达错误的消息字符串

然后运行结果会变成这样

发现没有,断言失败的时候,它把那个错误消息的文字报出来了,这样你就能更清楚地知道是哪里出错了