现在,让我们仔细看看测试结构的样子。 让我们从一个简单的测试用例开始,它将显示基本的PHPUnit测试结构。 以下代码片段是测试用于排序数组的两个PHP函数的一个非常基本的示例:asort()用于对数组进行排序并维护索引,而ksort()用于按键对数组进行排序。 首先,我们有一系列蔬菜,其中名称是关键,价格是价值:

<?php

class SecondTest extends PHPUnit_Framework_TestCase
{
public function testAsort ()
{
$vegetablesArray = array (
'carrot' => 1, 'broccoli' => 2.99,
'garlic' => 3.98, 'swede' => 1.75
);
$sortedArray = array (
'carrot' => 1, 'swede' => 1.75,
'broccoli' => 2.99, 'garlic' => 3.98
);
asort( $vegetablesArray, SORT_NUMERIC );
$this->assertSame( $sortedArray, $vegetablesArray );
} public function testKsort ()
{
$fruitsArray = array (
'oranges' => 1.75, 'apples' => 2.05,
'bananas' => 0.68, 'pear' => 2.75
);
$sortedArray = array (
'apples' => 2.05, 'bananas' => 0.68,
'oranges' => 1.75, 'pear' => 2.75
);
ksort( $fruitsArray, SORT_STRING );
$this->assertSame( $sortedArray, $fruitsArray );
}
}

如您所见,每个测试用例都是一个类。 类名应以Test结尾。 这是因为当您测试类时,测试类应该镜像测试类,并且测试类和测试套件之间的区别是测试添加到名称:

.
|-- src
'-- library
'-- Util
'-- File.php
|-- tests
'-- library
'-- Util
'-- FileTest.php

每个测试类也称为测试套件,它扩展了PHPUnit_Framework_TestCase类。 当然,您可以编写自己的修改或扩展的PHPUnit_ Framework_TestCase并调用它,例如,MyTestCase,但这个父类应该扩展原始的PHPUnit类。 这可以在以下类定义中看到:

abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test,PHPUnit_Framework_SelfDescribing

以下内容告诉您前面的类定义的作用:

  • abstract:这是因为你总是扩展PHPUnit_Framework_TestCase类而不直接执行这个类
  • 扩展PHPUnit_Framework_Assert:这是提供一组断言方法的类,例如assertTrue()和assertEquals()
  • 实现PHPUnit_Framework_Test:这是一个简单的接口,只包含一个方法run()来执行测试
  • 实现PHPUnit_Framework_SelfDescribing:这是另一个简单的接口,只包含一个方法toString()

PHPUnit不使用已经引入PHP 5.3的名称空间。 主要是为了向后兼容,PHPUnit在类名中使用下划线来匹配文件系统中的类位置。

1.定义测试方法

       每个测试方法名称都应该以test开头。 那么这个名字取决于你。 您可以镜像他们的测试类方法,但您可能需要更多测试。 每个测试方法都应该有一个解释性名称,这意味着您应该能够从名称中说出您正在测试的内容,例如testChangePassword()或testChangePasswordForLockedAcoounts()

 2.测试函数

       这是一个理论,现在我们来看看一个特定的现实生活中的例子。 让我们使用开发人员在求职面试中可以得到的以下问题,并通过此示例了解PHPUnit如何帮助我们解决问题或让我们确信我们找到了正确的解决方案。

任务是在PHP中编写一个函数,它返回有序数组中最大的连续整数和。

例如,如果输入为[0,1,2,3,6,7,8,9,11,12,14],则最大总和为6 + 7 + 8 + 9 = 30。

如您所见,它看起来并不特别困难。 您可以采取几种不同的方法。 写一些非常聪明的东西,使用蛮力和遍历数组,但任何有效的方法都是正确的答案。

现在,让我们来看看PHPUnit如何帮助解决这个问题。 首先,你必须停下来思考你在做什么 - 不仅仅是开始编写代码,并且在一段时间后迷失方向,不知道你想要实现什么。

那么你如何解决这个问题呢?

以下步骤是最好的方法:

1.使用PHP函数usort()使用用户定义的比较函数按值对数组进行排序。

2.然后返回已排序数组的最后一个元素,该元素将成为最大的组。

这是制定战略的重要一点。 现在,让我们将其转换为函数,而无需编写实现。 请考虑以下代码段:

<?php
/**
* 返回连续整数的最大总和
* @param array $inputArray
* @return array
*/
function sumFinder(array $inputArray) : array {}
/**
* 自定义数组比较方法
* @param array $a
* @param array $b
* @return int
*/
function compareArrays(array $a, array $b) : int {}

现在你有两个功能。 第一个函数使用PHP函数usort()将数组作为输入,第二个函数compareArrays()按组对数组进行排序。 然后第一个函数返回一个包含组名和sum的数组。

现在你知道函数的样子了。 让我们为它们编写测试,描述它们的行为方式,如下面的代码片段所示:

<?php
require_once 'SumFinder.php'; class SumFinderTest extends PHPUnit_Framework_TestCase
{
public function testSumFinder ()
{
$input = array ( 0, 1, 2, 3, 6, 7, 8, 9, 11, 12, 14 );
$result = array ( 'group' => '6, 7, 8, 9', 'sum' => 30 );
$this->assertEquals( $result, sumFinder( $input ) );
} public function testCompareArrays ()
{
$array1 = array ( 0, 1, 2, 3 );
$array2 = array ( 6, 7, 8, 9 );
// $array2 > $array1
$this->assertEquals( -1, compareArrays( $array1, $array2 ) );
// $array1 < $array2
$this->assertEquals( 1, compareArrays( $array2, $array1 ) );
// $array2 = $array2
$this->assertEquals( 0, compareArrays( $array2, $array2 ) );
}
}

如您所见,每个函数都有两个简单的测试。 第一个测试testSumFinder()验证主sumFinder()函数,第二个测试testCompareArrays()验证在使用usort()时数组是否正确排序。 现在您可以运行它们并查看以下结果:

FAILURES!
Tests: , Assertions: , Failures: .

牛逼! 这就是我们想要的:它失败了,因为我们必须编写一个实现。让我们从compareArrays()函数开始,如下面的代码片段所示:

<?php
/**
* 自定义数组比较方法
* @param array $a
* @param array $b
* @return int
*/
function compareArrays ( array $a, array $b )
{
$sumA = array_sum( $a );
$sumB = array_sum( $b );
if ($sumA == $sumB) {
return 0;
} else if ($sumA > $sumB) {
return 1;
} else {
return -1;
}
}

然后你可以运行testCompareArrays(),很好,它的工作方式如下面的输出:

OK (1 test, 3 assertions)

  现在我们可以转到sumFinder()实现,如下面的代码片段所示:

<?php
/**
* 返回连续整数的最大总和
* @param array $inputArray
* @return array
*/ function sumFinder ( array $inputArray ) : array
{
$arrayGroups = array ();
foreach ($inputArray as $element) {
//initial settings
if (!isset( $previousElement )) {
$previousElement = $element;
$arrayGroupNumber = 0;
}
if (( $previousElement + 1 ) != $element) {
$arrayGroupNumber += 1;
}
$arrayGroups[ $arrayGroupNumber ][] = $element;
$previousElement = $element;
}
usort( $arrayGroups, 'compareArrays' );
$highestGroup = array_pop( $arrayGroups );
return ( array (
'group' => implode( ', ',
$highestGroup ), 'sum' => array_sum( $highestGroup )
) );
}

运行上面的代码段时,您将获得以下结果:

OK (1 test, 1 assertion)

  这就是解决方案。 在这里,您应该看到单元测试的最大优势之一; 它会强迫您在开始编写代码或在实现之前阐明代码,考虑您正在做什么并有一个清晰的想法。

3.测试方法

       测试方法与测试函数非常相似,但是你可以做更多。过程编程没有任何问题,但是有很好的理由使用面向对象编程(OOP)。 PHP严格地说不是Java或C#等OOP语言,但这并不意味着你不能使用OOP。 当然可以,PHP有一个非常好的对象模型。 它是一个可靠的实现,具有您期望的所有主要功能。 OOP真正有用的地方在于组织具有所有OOP优势的代码,并且在编写测试时也有帮助。

PHPUnit支持测试类和对象。 在测试类时,PHPUnit和单元测试的真正优势在于您不仅可以测试每个方法,而且在必要时,您可以使用您的实现替换部分类以进行测试,例如,避免将数据存储在数据库中。 这称为测试双打,这些技术将在本书的后面部分进行描述。

在测试类方法时,建议仅测试公共方法。 据说尽可能多的代码应该进行测试后,这听起来有点奇怪。 为什么不为私有或受保护的方法编写测试? 原因是你应该只测试公共方法; 其他一切都只是你不应该担心的内部实现,即使它发生了变化,公共方法仍然应该以相同的方式运行。 如果私有/受保护的方法过于复杂,则可能表明它们应该拥有自己的类,或者您可以使用PHP反射并动态更改可访问性。

代码实现部分待续......

第二节 PHPUnit测试的剖析的更多相关文章

  1. Ionic 入门与实战之第二章第二节:Ionic 环境搭建之 Ionic Lab 使用

    原文发表于我的技术博客 本文是「Ionic 入门与实战」系列连载的第二章第二节,主要对 Ionic Lab 工具作了介绍,并讲解了其使用方法,这也是一个开发 Ionic 比较好的调试工具. 原文发表于 ...

  2. QQ登录整合/oauth2.0认证-03-对第二节的代码改进

    ---------------------------目录---------------------------------- QQ登录整合/oauth2.0认证-01-申请appkey和appid ...

  3. android内部培训视频_第二节 布局基础

    第二节:布局入门 一.线性布局 需要掌握的属性: 1.orientation:排列方式 vertical:垂直 Horizontal:水平 2.weight:水平布局的权重 3.gravity:子控件 ...

  4. phpunit测试学习 2 分类总结断言涉及哪些方面

    11:27 2015/12/9phpunit测试学习 2,  分类总结断言涉及哪些方面先推荐windows快速打开某处路径下的cmd,进入测试状态:可以在文件夹中,按住Shift+鼠标右键,这时候你就 ...

  5. phpunit测试学习 1:一点简单的扼要有用的东西的总结 一点入门认识

    16:45 2015/12/8phpunit测试学习 1:一点简单的扼要有用的东西的总结  一点入门认识 具体的入门安装和入门实践请参照文中的推荐博客或网上其他博客推荐博客,我感觉这几篇博客写得很不错 ...

  6. phpunit测试成功 phpunit测试实践代码

    16:12 2015/12/8phpunit测试成功,代码写在www目录下,以类名命名代码文件,我的文件名为 ArrayTest.php,类名为ArrayTest,内部写了简单的测试代码:<?p ...

  7. seajs第二节,seajs各模块依赖关系

    index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...

  8. 学习javascript基础知识系列第二节 - this用法

    通过一段代码学习javascript基础知识系列 第二节 - this用法 this是面向对象语言中的一个重要概念,在JAVA,C#等大型语言中,this固定指向运行时的当前对象.但是在javascr ...

  9. VUE2.0实现购物车和地址选配功能学习第二节

    第二节 创建VUE实例 购物车项目计划: 1.创建一个vue实例 2.通过v-for指令渲染产品数据 3.使用filter对金额和图片进行格式化 4.使用v-on实现产品金额动态计算 5.综合演示 ① ...

随机推荐

  1. 数据对齐 posix_memalign 函数详解

    对齐 数 据的对齐(alignment)是指数据的地址和由硬件条件决定的内存块大小之间的关系.一个变量的地址是它大小的倍数的时候,这就叫做自然对齐 (naturally aligned).例如,对于一 ...

  2. elsevier期刊要求翻译

    百度文库 http://wenku.baidu.com/view/e20a27e84afe04a1b071de4e.html 官网文档 http://www.elsevier.com/journals ...

  3. JavaWeb-拦截器,过滤器,监听器的区别和执行顺序

    一:拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,springmvc的aop中的前置通知和后置通知. 二: ...

  4. vs code配置c/c++调试环境+mingw+windows

    目录 1.安装codeblocks 2.配置mingw环境变量 3.配置.vscode文件夹的json文件 ref 1.安装codeblocks 我已经安装过vscode和c++扩展插件,现在需要g+ ...

  5. docker基础——关于安装、常用指令以及镜像制作初体验

    为什么使用docker docker就是一个轻量级的虚拟机,他解决的是服务迁移部署的时候环境配置问题.比如常见的web服务依赖于jdk.Tomcat.数据库等工具,迁移项目就需要在新的机器重新配置这些 ...

  6. Docker自学纪实(二)Docker基本操作

    安装docker 以CentOS7为例: 安装:yum -y install docker 启动:systemctl start docker 设置开机自启:systemctl enable dock ...

  7. python的多继承C3(mro)算法

    多继承的继承顺序按照C3算法进行顺序继承 例一 按照深度A类从左往右有三条可继承的"路" 先按照深度优先的算法,将每一路的每一个节点加到列表中 B = [B,D,F,H] C = ...

  8. strak组件(9):关键字搜索

    效果图: 在列表视图函数增加搜索功能. 新增函数 def get_search_list(self) 钩子方法,获取搜索条件 一.strak组件 strak/service/core_func.py ...

  9. linux通用GPIO驱动,写GPIO文件不立即生效问题解决

    Linux开发平台实现了通用GPIO的驱动,用户通过,SHell或者系统调用能控制GPIO的输出和读取其输入值.其属性文件均在/sys/class/gpio/目录下,该目录下有export和unexp ...

  10. Codeforces Round #462 (Div. 2) C DP

    C. A Twisty Movement time limit per test 1 second memory limit per test 256 megabytes input standard ...