一、概述

1. 什么是单元测试?

【百度百科】单元测试是对软件中的最小可测单元进行检查和验证。

是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。

2. 作用是什么?

【废话】检查软件、程序的可行性,稳定性。

通过单元测试能够避免在迭代、升级等过程中,引起重复的、多余的问题。

避免在别人修改代码的时候,影响到你的逻辑

3. 哪些程序需要写单元测试(PHP)?

【理想】理想的单元测试应当覆盖程序中所有可能的路径,包括正确的和错误的路径,个单元测试通常覆盖一个函数或方法中的一个特定路径。

【现实】model、helper、controller中的函数必须测试、路径覆盖到所有可能性

二、PHPUnit的安装与集成CI框架

略。。。。。后续再补

三、PHPUnit的使用

编写测试用例

测试的依赖关系 @depends

PHPUnit支持对测试方法之间的显式依赖关系进行声明。这种依赖关系并不是定义在测试方法的执行顺序中,而是允许生产者(producer)返回一个测试基境(fixture)的实例,并将此实例传递给依赖于它的消费者(consumer)们。

class StackTest extends PHPUnit_Framework_TestCase

{

public function testEmpty()

{

$stack = array();

$this->assertEmpty($stack);

return $stack;

}

/**

@depends testEmpty

*/

public function testPush(array $stack)

{

array_push($stack, 'foo');

$this->assertEquals('foo', $stack[count($stack)-1]);

$this->assertNotEmpty($stack);

return $stack;

}

/**

@depends testPush

*/

public function testPop(array $stack)

{

$this->assertEquals('foo', array_pop($stack));

$this->assertEmpty($stack);

}

}

?>

默认情况下,生产者所产生的返回值将“原样”传递给相应的消费者。这意味着,如果生产者返回的是一个对象,那么传递给消费者的将是一个指向此对象的引用。如果需要传递对象的副本而非引用,则应当用 @depends clone 替代 @depends。

数据供给器 @dataProvider

测试方法可以接受任意参数。用 @dataProvider 标注来指定使用哪个数据供给器方法。

数据供给器方法必须声明为 public,其返回值要么是一个数组,其每个元素也是数组;要么是一个实现了 Iterator 接口的对象,在对它进行迭代时每步产生一个数组。每个数组都是测试数据集的一部分,将以它的内容作为参数来调用测试方法。

class DataTest extends PHPUnit_Framework_TestCase

{

/**

@dataProvider additionProvider

*/

public function testAdd($a, $b, $expected)

{

$this->assertEquals($expected, $a + $b);

}

public function additionProvider()

{

return array(

array(0, 0, 0),

array(0, 1, 1),

array(1, 0, 1),

array(1, 1, 3)

);

}

}

?>

也可以是这样:

class DataTest extends PHPUnit_Framework_TestCase

{

/**

* @dataProvider additionProvider

*/

public function testAdd($a, $b, $expected)

{

$this->assertEquals($expected, $a + $b);

}

public function additionProvider()

{

return array(

'adding zeros' => array(0, 0, 0),

'zero plus one' => array(0, 1, 1),

'one plus zero' => array(1, 0, 1),

'one plus one' => array(1, 1, 3)

);

}

}

?>

对PHP错误进行测试

默认情况下,PHPUnit 将测试在执行中触发的 PHP 错误、警告、通知都转换为异常。利用这些异常,就可以,比如说,预期测试将触发 PHP 错误

class ExpectedErrorTest extends PHPUnit_Framework_TestCase

{

/**

@expectedException PHPUnit_Framework_Error

*/

public function testFailingInclude()

{

include 'not_existing_file.php';

}

}

?>

测试

phpunit -d error_reporting=2 ExpectedErrorTest

PHPUnit 5.2.0 by Sebastian Bergmann and contributors.

.

Time: 0 seconds, Memory: 5.25Mb

OK (1 test, 1 assertion)

命令行测试执行器

说明

PHPUnit 测试执行器可通过phpunit 调用,例如在CI中:

tongkundeMacBook-Pro:www tongkun$ cd tests/

tongkundeMacBook-Pro:tests tongkun$ phpunit

PHPUnit 5.0.0 by Sebastian Bergmann and contributors.

............. 13 / 13 (100%)

Time: 195 ms, Memory: 17.50Mb

OK (13 tests, 8 assertions)

说明:

先进入测试的根目录,执行phpunit 命令,后面可跟具体的目录或文件,也可不跟,如果没有则会对当前目录的所有文件执行单元测试,对于每个测试的运行,PHPUnit命令行工具会输出一个字符来指示进展:

. 当测试陈宫时输出

F 当测试方法运行过程中一个断言失败时输出,例如一个失败的assertEquals()调用

E 当测试方法运行过程中产生一个错误时输出,错误是指意料之外的异常(exception)或者PHP错误

R 当测试被标记有风险时输出

S 当测试跳出时输出

I 当测试被标记不完整或为实现时输出

常用命令行选项

--coverage-clover:为运行的测试生成带有代码覆盖率信息的 XML 格式的日志文件

--coverage-html:生成 HTML 格式的代码覆盖率报告

--coverage-php:生成一个序列化后的 PHP_CodeCoverage 对象,此对象含有代码覆盖率信息

--log-json:生成 JSON 格式的日志文件

--filter:只运行名称与给定模式匹配的测试。如果模式未闭合包裹于分隔符,PHPUnit 将用 / 分隔符对其进行闭合包裹

tongkundeMacBook-Pro:tests tongkun$ phpunit --filter 'WelcomeTest::testTest'

PHPUnit 5.0.0 by Sebastian Bergmann and contributors.

... 3 / 3 (100%)

Time: 148 ms, Memory: 16.75Mb

OK (3 tests, 3 assertions)

这样测试的就是WelcomeTest类中的testTest函数,过滤模式的例子有很多,详见文档官方

--colors:使用彩色输出。Windows下,用 ANSICON 或 ConEmu。

本选项有三个可能的值:

never: 完全不使用彩色输出。当未使用 --colors 选项时,这是默认值。

auto: 如果当前终端不支持彩色、或者输出被管道输出至其他命令、或输出被重定向至文件时,不使用彩色输出,其余情况使用彩色。

always: 总是使用彩色输出,即使当前终端不支持彩色、输出被管道输出至其他命令、或输出被重定向至文件。

当使用了 --colors 选项但未指定任何值时,将选择 auto 做为其值。

--stop-on-error:首次错误出现后停止执行。

--stop-on-failure:首次错误或失败出现后停止执行。

--stop-on-risky:首次碰到有风险的测试时停止执行。

--stop-on-risky:首次碰到有风险的测试时停止执行。

--stop-on-incomplete首次碰到不完整的测试时停止执行。

--repeat:将测试重复运行指定次数。

tongkundeMacBook-Pro:tests tongkun$ phpunit --repeat 10

PHPUnit 5.0.0 by Sebastian Bergmann and contributors.

............................................................... 63 / 130 ( 48%)

............................................................... 126 / 130 ( 96%)

.... 130 / 130 (100%)

Time: 456 ms, Memory: 26.25Mb

OK (130 tests, 80 assertions)

--tap:使用 Test Anything Protocol (TAP) 报告测试进度

tongkundeMacBook-Pro:tests tongkun$ phpunit --tap

TAP version 13

ok 1 - CI_Unit_Test_class_Test::test_CI_Unit_Test_Class

ok 2 - SomeControllerTest::testWelcomeController

ok 3 - WelcomeTest::testIndex

ok 4 - WelcomeTest::testTest

ok 5 - WelcomeTest::testOutput

ok 6 - WelcomeTest::testTest1

ok 7 - WelcomeTest::testTest2

ok 8 - HelperTest::testSampleFunction

ok 9 - SomeLibTest::testMethod

ok 10 - M_user_masterTest::testSelect

ok 11 - M_user_masterTest::testInsert

ok 12 - PHPTest::testFunctionJsonEncode

ok 13 - PHPTest::testPhpVersion

1..13

--configuration, -c:从 XML 文件中读取配置信息。更多细节请参见附录 C。

如果 phpunit.xml 或 phpunit.xml.dist (按此顺序)存在于当前工作目录并且未使用 --configuration,将自动从此文件中读取配置。

tongkundeMacBook-Pro:tests tongkun$ phpunit --configuration phpunit.xml

PHPUnit 5.0.0 by Sebastian Bergmann and contributors.

............. 13 / 13 (100%)

Time: 209 ms, Memory: 17.50Mb

OK (13 tests, 8 assertions)

--no-configuration:忽略当前工作目录下的 phpunit.xml 与 phpunit.xml.dist。

四、基境(fixture)

什么是基境?

“基境”就是编写代码来将整个场景设置成某个已知的状态,并在测试结束后将其复原到初始状态。这个已知的状态称为测试的 基境(fixture)。

基境的建立

PHPUnit 支持共享建立基境的代码。在运行某个测试方法前,会调用一个名叫 setUp() 的模板方法。setUp() 是创建测试所用对象的地方。当测试方法运行结束后,不管是成功还是失败,都会调用另外一个名叫 tearDown() 的模板方法。tearDown() 是清理测试所用对象的地方。

class StackTest extends PHPUnit_Framework_TestCase

{

protected $stack;

protected function setUp()

{

$this->stack = array();

}

public function testEmpty()

{

$this->assertTrue(empty($this->stack));

}

public function testPush()

{

array_push($this->stack, 'foo');

$this->assertEquals('foo', $this->stack[count($this->stack)-1]);

$this->assertFalse(empty($this->stack));

}

public function testPop()

{

array_push($this->stack, 'foo');

$this->assertEquals('foo', array_pop($this->stack));

$this->assertTrue(empty($this->stack));

}

}

?>

测试类的每一个方法都会运行一次setUp()和tearDown()模板方法(同时,每个测试方法都在一个全新的测试类实例上运行),

另外,setUpBeforeClass() 与 tearDownAfterClass() 模板方法将分别在测试用例类的第一个测试运行之前和测试用例类的最后一个测试运行之后调用。基境共享可以在共享数据库连接时使用;

五、组织测试

用文件系统来编排测试套件

例如:

phpunit controllers/WelcomeTest.php

用 XML 配置来编排测试套件

//配置文件

colors="true" //颜色

stopOnFailure="false" //出错后是否终止

bootstrap="../application/third_party/CIUnit/bootstrap_phpunit.php"> //bootstrap 地址

//测试套件

controllers //要测试的目录

helpers

libs

models

system

vendor

libs

controllers

fixtures

models

helpers

六、有风险的测试

无用测试

PHPUnit 可以更严格对待事实上不测试任何内容的测试。此项检查可以用命令行选项 --report-useless-tests 或在 PHPUnit 的 XML 配置文件中设置 beStrictAboutTestsThatDoNotTestAnything="true" 来启用。

在启用本项检查后,如果某个测试未进行任何断言,它将被标记为有风险。仿件对象中的预期和诸如 @expectedException 这样的标注同样视为断言。

测试执行期间产生的输出

PHPUnit 可以更严格对待测试执行期间产生的输出。 此项检查可以用命令行选项 --disallow-test-output 或在 PHPUnit 的 XML 配置文件中设置 beStrictAboutOutputDuringTests="true" 来启用。

在启用本项检查后,如果某个测试产生了输出,例如,在测试代码或被测代码中调用了 print,它将被标记为有风险。

七、未完成的测试与跳过的测试

未完成的测试

开始写新的测试用例类时,可能想从写下空测试方法开始,比如:

public function testSomething()

{

}

假如把成功的测试视为绿灯、测试失败视为红灯,那么还额外需要黄灯来将测试标记为未完成或尚未实现。PHPUnit_Framework_IncompleteTest 是一个标记接口,用于将测试方法抛出的异常标记为测试未完成或目前尚未实现而导致的结果。PHPUnit_Framework_IncompleteTestError 是这个接口的标准实现。

例如:我们有一个测试文件,contrllers/WelcomeTest.php,其中有一个测试方法,通过在测试方法中调用markTestIncomplete()将这个测试标记为未完成。

public function testTest() {

$this->assertTrue(true,'这里可以正常工作');

$this->markTestIncomplete('此测试尚未实现');

}

在PHPUnit命令行测试执行器中输出,未完成的测试标记为1, 如下:

localhost:tests tongkun$ phpunit

PHPUnit 5.0.0 by Sebastian Bergmann and contributors.

R..I...RRRR.. 13 / 13 (100%)

Time: 187 ms, Memory: 17.75Mb

OK, but incomplete, skipped, or risky tests!

Tests: 13, Assertions: 8, Incomplete: 1, Risky: 5.

跳过测试

如上,如果有些测试需要某些环境或者配置才能完成,则可选择跳过,通过调用 markTestSkipped() 方法来测试

用 @requires 来跳过测试

除了上述方法,还可以用 @requires 标注来表达测试用例的一些常见前提条件。

事例:

例 7.3: 用 @requires 来跳过测试

/**

* @requires extension mysqli

*/

class DatabaseTest extends PHPUnit_Framework_TestCase

{

/**

* @requires PHP 5.3

*/

public function testConnection()

{

// 测试要求有 mysqli 扩展,并且 PHP >= 5.3

}

// ... 所有其他要求有 mysqli 扩展的测试

}

?>

要求安装mysqli苦战和php 5.3 才能执行

#常用断言

前边废话一篇,终于到了关键的断言部分,断言可以说是单元测试的核心,通过断言的校验,保证程序的正确运行,并输出正确的值。

assertArrayHasKey()

assertArrayHasKey(mixed $key, array $array[, string $message = ''])

当 $array 不包含 $key 时报告错误,错误讯息由 $message 指定。

assertArrayNotHasKey() 是与之相反的断言,接受相同的参数。

assertContains()

assertContains(mixed $needle, Iterator|array $haystack[, string $message = ''])

当 $needle 不是 $haystack的元素时报告错误,错误讯息由 $message 指定。

assertNotContains() 是与之相反的断言,接受相同的参数。

assertContains(string $needle, string $haystack[, string $message = '', boolean $ignoreCase = FALSE])

当 $needle 不是 $haystack 的子字符串时报告错误,错误讯息由 $message 指定。

assertContainsOnly()

assertContainsOnly(string $type, Iterator|array $haystack[, boolean $isNativeType = NULL, string $message = ''])

当 $haystack 并非仅包含类型为 $type 的变量时报告错误,错误讯息由 $message 指定。

$isNativeType 是一个标志,用来表明 $type 是否是原生 PHP 类型。

assertEmpty()

assertEmpty(mixed $actual[, string $message = ''])

当 $actual 非空时报告错误,错误讯息由 $message 指定。

assertNotEmpty() 是与之相反的断言,接受相同的参数。

assertAttributeEmpty() 和 assertAttributeNotEmpty() 是便捷包装(convenience wrapper),可以应用于某个类或对象的某个 public、protected 或 private 属性。

assertEquals()

assertEquals(mixed $expected, mixed $actual[, string $message = ''])

当两个变量 $expected 和 $actual 不相等时报告错误,错误讯息由 $message 指定。

assertNotEquals() 是与之相反的断言,接受相同的参数。

注意特定类型的比较(浮点型等),详见文档

assertFalse()

assertFalse(bool $condition[, string $message = ''])

当 $condition 为 TRUE 时报告错误,错误讯息由 $message 指定。

assertNotFalse() 是与之相反的断言,接受相同的参数。

assertNull()

assertNull(mixed $variable[, string $message = ''])

当 $actual 不是 NULL 时报告错误,错误讯息由 $message 指定。

assertNotNull() 是与之相反的断言,接受相同的参数。

assertRegExp()

assertRegExp(string $pattern, string $string[, string $message = ''])

当 $string 不匹配于正则表达式 $pattern 时报告错误,错误讯息由 $message 指定。

assertNotRegExp() 是与之相反的断言,接受相同的参数。

assertStringMatchesFormat()

assertStringMatchesFormat(string $format, string $string[, string $message = ''])

当 $string 不匹配于 $format 定义的格式时报告错误,错误讯息由 $message 指定。

assertStringNotMatchesFormat() 是与之相反的断言,接受相同的参数。

assertSame()

assertSame(mixed $expected, mixed $actual[, string $message = ''])

当两个变量 $expected 和 $actual 的值与类型不完全相同时报告错误,错误讯息由 $message 指定。

assertNotSame() 是与之相反的断言,接受相同的参数。

assertAttributeSame() 和 assertAttributeNotSame() 是便捷包装(convenience wrapper),以某个类或对象的某个 public、protected 或 private 属性作为实际值来进行比较。

assertTrue()

assertTrue(bool $condition[, string $message = ''])

当 $condition 为 FALSE 时报告错误,错误讯息由 $message 指定。

assertNotTrue() 是与之相反的断言,接受相同的参数。

mac php 单元测试,PHPUnit单元测试相关推荐

  1. php单元测试工具入门,PHPUnit 单元测试安装与使用入门教程

    本文实例讲述了PHPUnit 单元测试安装与使用.分享给大家供大家参考,具体如下: 一.官网下载对应 PHP 版本的代码库 二.安装 PHPUnit 官网提供了两种方法安装 1. PHP Archiv ...

  2. PHPUnit单元测试

    PHPUnit单元测试 一.概述 1. 什么是单元测试? [百度百科]单元测试是对软件中的最小可测单元进行检查和验证. 是开发者编写的一小段代码,用于检验被测代码的一个很小的.很明确的功能是否正确. ...

  3. 单元测试 php,PHP单元测试PHPUnit简单用法示例

    本文实例讲述了PHP单元测试PHPUnit简单用法.分享给大家供大家参考,具体如下: windows开发环境下,PHP使用单元测试可以使用PHPUnit. 安装 首先下载PHPUnit,官网:http ...

  4. php怎么做单元测试,php单元测试怎么写

    windows开发环境下,PHP使用单元测试可以使用PHPUnit. 推荐阅读:php服务器 安装PHPUnit 使用 composer 方式安装 PHPUnit,其他安装方式请看这里composer ...

  5. @sql 单元测试_SQL单元测试:使用异常

    @sql 单元测试 With this article, we will complete our journey with SQL Unit Testing. But first, let's re ...

  6. @sql 单元测试_SQL单元测试最佳实践

    @sql 单元测试 SQL unit testing is a testing method which allows us to test the smallest, atomic programm ...

  7. 高质量的单元测试 Spock单元测试框架详讲

    文章目录 方法篇 为什么需要单元测试 单元测试的定义 单元测试与其他测试的区别 单元测试的作用 关于单元测试的成本 如何写好单元测试 什么场景适合单元测试 单元测试的粒度 关于TDD TDD的三定律 ...

  8. PHPUnit单元测试 - 我看过的PHP开源框架

    2019独角兽企业重金招聘Python工程师标准>>> PHPUnit 作为XUnit系列,大家应该对单元测试体系都比较了解,这里不再详细说明,感兴趣的同学可以参考PHPUnit官方 ...

  9. phpunit 单元测试案例--签到任务

    因工作需要,最近要写单元测试了,这里算是一个记录的过程吧,慢慢记录,慢慢学习,慢慢总结,早点把这块的信息熟悉起来~~ 之前也写过简单的单元测试的一些小的说明,但是现在的是比较具体的例子了! 这里要列举 ...

  10. PHPUNIT 单元测试

    在windows上的安装可以参考其手册 首先下载phpunit.phar文件 1. 为php的二进制可执行文件建立 一个目录,如C:\bin 2. 将C:\bin添加到系统环境变量中, 3. 打开命令 ...

最新文章

  1. 自动设置为兼容模式html5,HTML5中怎么调兼容性?
  2. Mysql主主复制架构配置
  3. java平衡二叉树,最全Java知识总结
  4. linux 系统网络服务器组建,配置和管理实训教程 pdf,Linux网络服务器配置管理项目实训教程2...
  5. 如何使用 rsync 备份 Linux 系统的一些介绍
  6. BZOJ 3436: 小K的农场( 差分约束 )
  7. css 写打印样式问题
  8. linux线程间同步(1)读写锁
  9. [Python]网络爬虫(11):亮剑!爬虫框架小抓抓Scrapy闪亮登场!
  10. PHP双码率视频云转码服务系统源码 m3u8切片秒切
  11. linux i o端口编程,linux 操作 I/O 端口
  12. Spark与MR的区别
  13. NOIP模拟赛(洛谷11月月赛)
  14. 2.移植3.4内核-支持烧写yaffs2,裁剪内核并制作补丁
  15. GIS开发实习地图符号图式制作
  16. 如何获得免费卡巴斯基激活码?
  17. ZYNQ PL 添加IP 串口UART AXI UART16550
  18. 百位LOL英雄联盟角色合集
  19. eclipse neno高级安装
  20. JAVA 将图片转换成pdf文件

热门文章

  1. mysql ndb安装_MySQL NDB源码安装
  2. 数据产品经理的具象化
  3. [新手教程]如何使用 AirDrop 发送文件
  4. 敬业签桌面便签软件:该openid已被使用,无法绑定!(适用QQ微信互联登录解绑)
  5. 扩展卢卡斯 (板子)
  6. macos 系统固件 路径_iTunes下载的固件在哪里?iTunes固件文件路径详解
  7. shiny改写服务器文件,Shiny生产环境部署与共享
  8. shiny导出html,将R Shiny页面导出为PDF
  9. 用Python分析北京二手房房价
  10. IntelliJ IDEA 在 Project 选项卡中查找快捷键