该软件包已被弃用,请查看感染。
Humbug 是 PHP 的突变测试框架。它目前正在开发中,因此,虽然它实际上运行得很好,但它仍然存在一些缺陷,一群小黄人正在努力解决这些问题。如果它掉出门外,我们已警告您;)。
$ git remote set-url upstream https://github.com/humbug/humbug.git
将upstream
替换为您本地使用的遥控器的名称; upstream
是常用的,但您可能正在使用其他东西。您还可以使用不同的 URL(例如 [email protected]:mockery/mockery.git)。运行git remote -v
查看您实际使用的内容。
目录
简而言之,突变测试就是让你的单元测试物有所值。它涉及将小缺陷注入源代码,然后检查单元测试是否注意到。如果确实如此,那么您的单元测试已经“杀死”了该突变。如果不是,则该突变就逃脱了检测。由于单元测试的目的是防止回归,因此没有注意到真正的回归通过将是一件坏事!
代码覆盖率可以告诉您测试正在执行哪些代码,而突变测试旨在帮助您判断单元测试的实际执行情况以及可以改进的地方。
我已经更详细地写了为什么突变测试值得拥有:谎言,该死的谎言和代码覆盖率:走向突变测试
Humbug 是一个开源项目,欢迎任何人提出拉取请求和问题。在打开拉取请求之前,请阅读我们简短的贡献指南。
您可以使用 Composer 克隆并安装 Humbug 的依赖项:
git clone https://github.com/humbug/humbug.git
cd humbug
/path/to/composer.phar install
humbug 命令现在位于 bin/humbug。
如果你不想直接跟踪master分支,你可以安装Humbug phar,如下所示:
wget https://padraic.github.io/humbug/downloads/humbug.phar
wget https://padraic.github.io/humbug/downloads/humbug.phar.pubkey
# If you wish to make humbug.phar directly executable
chmod +x humbug.phar
在 Windows 上,您可以使用浏览器或使用以下命令从 Powershell v3 下载,其中wget
是Invoke-WebRequest
的别名:
wget https://padraic.github.io/humbug/downloads/humbug.phar -OutFile humbug.phar
wget https://padraic.github.io/humbug/downloads/humbug.phar.pubkey -OutFile humbug.phar.pubkey
如果您无法使用 Powershell v2:
$client = new-object System.Net.WebClient
$client .DownloadFile( " https://padraic.github.io/humbug/downloads/humbug.phar " , " humbug.phar " )
$client .DownloadFile( " https://padraic.github.io/humbug/downloads/humbug.phar.pubkey " , " humbug.phar.pubkey " )
phar 使用 openssl 私钥进行签名。您需要始终将 pubkey 文件存储在 phar 文件旁边才能使用它。例如,如果将humbug.phar
重命名为humbug
,则还将密钥从humbug.phar.pubkey
重命名为humbug.pubkey
。
phar 版本目前是手动完成的,因此它们不会以与 git master 相同的频率更新。要更新当前的 Phar,只需运行:
./humbug.phar self-update
注意:使用 phar 意味着修复可能需要更长的时间才能到达您的版本,但可以更好地保证拥有稳定的开发版本。公钥仅下载一次。通过自我更新重复使用它来验证未来的 Phar 版本。
一旦版本开始趋于稳定,就会有 alpha、beta、RC 和最终版本。您的开发跟踪 phar 文件将自动自我更新,直到达到稳定版本。如果您希望继续跟踪开发级别阶段,您将需要使用稳定性标志之一来表明这一点:
./humbug.phar self-update --dev
如果您在自我更新时遇到任何意外openssl
或 SSL 错误的问题,请确保您已启用openssl
扩展。在 Windows 上,您可以通过在命令行上添加或取消注释 PHP 的php.ini
文件中的以下行来执行此操作(如果与您的 http 服务器的文件不同):
extension=php_openssl.dll
由于缺少证书,可能会出现某些其他 SSL 错误。您可以通过查找它们在系统上的位置(例如C:/xampp/php/ext/cacert.pem
)或从 http://curl.haxx.se/ca/cacert.pem 下载副本来纠正此问题。然后确保以下选项正确指向该文件:
openssl.cafile=C:/path/to/cacert.pem
由于 Humbug 的依赖项与最新版本挂钩,因此将 Humbug 添加到composer.json 可能会引起冲突。当发生这种情况时,首选上述两种安装方法。但是,您可以像任何其他通用工具一样全局安装它:
composer global require ' humbug/humbug=~1.0@dev '
如果您以前没有这样做过...将其添加到~/.bash_profile
(或~/.bashrc
):
export PATH= ~ /.composer/vendor/bin: $PATH
Humbug 目前适用于 PHP 5.4 或更高版本。
Humbug 仍在开发中,因此,重复一遍,要小心粗糙的边缘。
要在项目中配置 humbug,您可以运行:
humbug configure
该工具将询问创建 Humbug 配置文件 ( humbug.json.dist
) 所需的一些问题。
在项目的基本目录中创建一个humbug.json.dist
文件:
{
"timeout" : 10 ,
"source" : {
"directories" : [
"src"
]
} ,
"logs" : {
"text" : "humbuglog.txt" ,
"json" : "humbuglog.json"
}
}
您可以将humbug.json.dist
提交到 VCS 并使用humbug.json
文件在本地覆盖它。
根据需要进行编辑。如果您没有定义至少一个日志,则有关逃逸突变体的详细信息将不可用。文本日志是人类可读的。如果源文件存在于基本目录中,或者必须排除源目录中的文件,则可以添加排除模式(这是一种针对基本目录中的文件的排除模式,其中排除了composer供应商和测试目录):
{
"timeout" : 10 ,
"source" : {
"directories" : [
"."
] ,
"excludes" : [
"vendor" ,
"Tests"
]
} ,
"logs" : {
"text" : "humbuglog.txt"
}
}
如果您必须从项目的基目录中从另一个目录运行测试,那么您也可以发出信号。您不需要从项目基目录以外的任何目录运行 Humbug。
{
"chdir" : "tests" ,
"timeout" : 10 ,
"source" : {
"directories" : [
"src"
] ,
}
}
确保您的测试全部处于通过状态(允许不完整和跳过的测试)。如果您的任何测试失败,Humbug 就会退出。
在项目的基本目录中(使用 PHAR 下载)的神奇命令是:
./humbug.phar
或者如果您刚刚克隆了 Humbug:
../humbug/bin/humbug
或者如果您将 Humbug 作为作曲家依赖项添加到您的项目中:
./vendor/bin/humbug
您还可以通过 phpdbg 运行 Humbug,而不是带有 xdebug 扩展的 php:
phpdbg -qrr humbug.phar
如果一切顺利,您将得到类似以下内容的信息:
_ _ _
| || |_ _ _ __ | |__ _ _ __ _
| __ | || | ' | '_ || / _` |
|_||_|_,_|_|_|_|_.__/_,___, |
|___/
Humbug version 1.0-dev
Humbug running test suite to generate logs and code coverage data...
361 [==========================================================] 28 secs
Humbug has completed the initial test run successfully.
Tests: 361 Line Coverage: 64.86%
Humbug is analysing source files...
Mutation Testing is commencing on 78 files...
(.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out)
.....M.M..EMMMMMSSSSMMMMMSMMMMMSSSE.ESSSSSSSSSSSSSSSSSM..M.. | 60 ( 7/78)
...MM.ES..SSSSSSSSSS...MMM.MEMME.SSSS.............SSMMSSSSM. | 120 (12/78)
M.M.M...TT.M...T.MM....S.....SSS..M..SMMSM...........M...... | 180 (17/78)
MM...M...ESSSEM..MMM.M.MM...SSS.SS.M.SMMMMMMM..SMMMMS....... | 240 (24/78)
.........SMMMSMMMM.MM..M.SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS | 300 (26/78)
SSSSSSSSM..E....S......SS......M.SS..S..M...SSSSSSSS....MMM. | 360 (37/78)
.M....MM..SM..S..SSSSSSSS.EM.S.E.M............M.....M.SM.M.M | 420 (45/78)
..M....MMS...MMSSS................M.....EME....SEMS...SSSSSS | 480 (52/78)
SSSSS.EMSSSSM..M.MMMM...SSE.....MMM.M..MM..MSSSSSSSSSSSSSSSS | 540 (60/78)
SSS....SSSSSSSSMM.SSS..........S..M..MSSMS.SSSSSSSSSSSSSSSSS | 600 (68/78)
......E...M..........SM.....M..MMMMM.MMMMMSSSSSSSM.SS
653 mutations were generated:
284 mutants were killed
218 mutants were not covered by tests
131 covered mutants were not detected
17 fatal errors were encountered
3 time outs were encountered
Metrics:
Mutation Score Indicator (MSI): 47%
Mutation Code Coverage: 67%
Covered Code MSI: 70%
Remember that some mutants will inevitably be harmless (i.e. false positives).
Humbug results are being logged as JSON to: log.json
Humbug results are being logged as TEXT to: log.txt
解释一下可能神秘的进度输出:
杀死、错误和超时都被计为检测到的突变。如果 Humbug 本身遇到内部错误,即在此处将错误报告为问题,我们会在日志中报告错误!
示例摘要结果报告了许多指标分数:
如果您检查这些指标,就会发现最突出的问题是 47% 的 MSI 比报告的 65% 的代码覆盖率低 18 个百分点。这些单元测试的效果远不如单独的代码覆盖率所能检测到的有效。
解释这些结果需要一些背景。日志将列出所有未检测到的突变,作为与原始源代码的差异。检查这些将进一步了解哪些特定突变未被检测到。
除了通常与任何 Symfony 控制台应用程序关联的命令行选项外,Humbug 还有一些值得注意的命令行选项。
您可以手动设置任何单个测试的超时阈值:
humbug --timeout=10
如果您只对更改文件的子集感兴趣,则可以传递任意数量的--file
选项,其中包含简单文件名、glob 或正则表达式。基本上,这些都被传递给 Symfony Finder 的name()
方法。
humbug --file=NewClass.php --file= * Driver.php
这绝不限制对整个测试套件的初始 Humbug 检查,该测试套件仍然完整执行,以确保所有测试在继续之前都正确通过。
如果您只想更改几个特定文件,则可以传递任意数量的包含完整路径文件名的--path
选项。此选项将传递到过滤器Closure
,它将使用 config 和/或--file
选项找到的文件与使用--path
选项提供的文件相交。
humbug --path=src/Data/NewClass.php --path=src/Driver/Driver.php
注意:这绝不限制对整个测试套件的初始 Humbug 检查,该测试套件仍会完整执行,以确保所有测试在继续之前都正确通过。
增量分析 (IA) 是一种实验性的未完成操作模式,其中结果在运行之间本地缓存,并在有意义的地方重用。目前,此模式通过消除测试运行来非常简单地运行,其中自上次运行以来,正在变异的直接文件和变异行的相关测试都没有被修改(通过比较所涉及文件的 SHA1 确定)。
humbug --incremental
IA 模式为相对稳定的代码库提供了显着的性能提升,您可以自由地测试它并了解它在现实生活中的表现。将来,它确实需要考虑包含父类、导入特征及其直接依赖项的类的文件中的更改,所有这些都会对任何给定对象的行为产生影响。
IA 使用本地永久缓存,例如/home/padraic/.humbug
。
突变测试传统上进展缓慢。其概念是针对生成的每个突变重新运行测试套件。为了显着加快速度,Humbug 执行以下操作:
虽然所有这些都会加快 Humbug 的速度,但请注意,Humbug 的运行速度会比单元测试慢。 2 秒的测试套件可能需要 30 秒来进行突变测试。或者5分钟。这一切都取决于代码行之间的相互作用、测试数量、代码覆盖级别以及代码和测试的性能。
Humbug 实现了一套基本的 Mutators,它本质上告诉我们何时可以对特定的 PHP 令牌进行突变,并将该突变应用于令牌数组。
注意:函数(而不是类方法)中保存的源代码此时不会发生变化。
二进制算术:
原来的 | 变异的 | 原来的 | 变异的 |
---|---|---|---|
+ | - | /= | *= |
- | + | %= | *= |
* | / | **= | /= |
/ | * | & | | |
% | * | | | & |
** | / | ^ | & |
+= | -= | ~ | |
-= | += | >> | << |
*= | /= | << | >> |
布尔替换:
这暂时包含逻辑变异器。
原来的 | 变异的 |
---|---|
真的 | 错误的 |
错误的 | 真的 |
&& | || |
|| | && |
和 | 或者 |
或者 | 和 |
! |
条件边界:
原来的 | 变异的 |
---|---|
> | >= |
< | <= |
>= | > |
<= | < |
否定条件句:
原来的 | 变异的 | 原来的 | 变异的 |
---|---|---|---|
== | != | > | <= |
!= | == | < | >= |
<> | == | >= | < |
=== | !== | <= | > |
!== | === |
增量:
原来的 | 变异的 |
---|---|
++ | -- |
-- | ++ |
返回值:
原来的 | 变异的 | 原来的 | 变异的 |
---|---|---|---|
返回真; | 返回假; | 返回1.0>; | 返回-(+1); |
返回假; | 返回真; | 返回$这个; | 返回空值; |
返回0; | 返回1; | 返回函数(); | 功能();返回空值; |
返回 ; | 返回0; | 返回新类; | 新班级;返回空值; |
返回0.0; | 返回 1.0; | 返回( Anything ); | ( Anything );返回空值; |
返回 1.0; | 返回0.0; |
文字数字:
原来的 | 变异的 |
---|---|
0 | 1 |
1 | 0 |
智力 > 1 | 智力+1 |
浮点数 >= 1 / <= 2 | 浮动+1 |
浮动 > 2 | 1 |
如果语句:
所有 if 语句大部分都被以前的变异器覆盖,但也有一些特殊情况,例如使用本机函数或类方法而不进行任何比较或操作,例如is_int()
或in_array()
。这不会涵盖文件中定义的函数,因为它们直到运行时才存在(还有其他工作要做!)。
原来的 | 变异的 |
---|---|
如果(is_int(1)) | if(!is_int(1)) |
随着时间的推移,将会添加更多的 Mutators。
bin/humbug stats ../my-project/humbuglog.json ../my-project/list-of-classes.txt --skip-killed=yes [-vvv]
解析 humbuglog.json 或自定义命名 JSON 日志中的统计信息。
CLI 参考:
humbug stats [humbuglog.json location] [class list location] [--skip-killed = yes] [-vvv]
humbuglog.json location, defaults to ./humbuglog.json
class list location, a path to a text file containing full class names, one per line.
only this files-related stats would be shown
--skip-killed=yes is used to completely skip output of "killed" section
various verbosity levels define amount of info to be displayed:
by default, there's one line per class with amount of mutants killed/escaped/errored/timed out (depending on output section)
-v adds one line per each mutant with line number and method name
-vv adds extra line for each mutant, displaying diff view of line mutant is detected in
-vvv shows full diff with several lines before and after
这可以通过在 humbug 的目录中运行来在 humbug 本身上进行测试:
bin/humbug bin/humbug 统计信息 [-vvv]
这是已知问题的简短列表:
由 Craig Davis 提供,他看到了曾经空的存储库的潜力:P。
.:::::::::::...
.::::::::::::::::::::.
.::::::::::::::::::::::::.
::::::::::::::::::::::::::::.
::::::::::::::::::::::::::::::: .,uuu ...
:::::::::::::::::::::::::::::::: dHHHHHLdHHHHb
....:::::::'` ::::::::::::::::::' uHHHHHHHHHHHHHF
.uHHHHHHHHH' ::::::::::::::`. uHHHHHHHHHHHHHP"
HHHHHHHHHHH `:::::::::::',dHHuHHHHHHHHP".g@@g
J"HHHHHHHHHP 4H ::::::::' u$$$.
".HHHHHHHHP" .,uHP :::::' uHHHHHHHHHHP"",e$$$$$c
HHHHHHHF' dHHHHf `````.HHHHHHHHHHP",d$$$$$$$P%C
.dHHHP"" JHHHHbuuuu,JHHHHHHHHP",d$$$$$$$$$e=,z$$$$$$$$ee..
"" .HHHHHHHHHHHHHHHHHP",gdP" ..3$$$Jd$$$$$$$$$$$$$$e.
dHHHHHHHHHHHHHHP".edP " .zd$$$$$$$$$$$"3$$$$$$$$c
`???""??HHHHP",e$$F" .d$,?$$$$$$$$$$$$$F d$$$$$$$$F"
?be.eze$$$$$".d$$$$ $$$E$$$$P".,ede`?$$$$$$$$
4."?$$$$$$$ z$$$$$$ $$$$r.,.e ?$$$$ $$$$$$$$$
'$c "$$$$ .d$$$$$$$ 3$$$.$$$$ 4$$$ d$$$$P"`,,
"""- "$$".`$$" " $$f,d$$P".$$P zeee.zd$$$$$.
ze. .C$C"=^" ..$$$$$$P".$$$'e$$$$$P?$$$$$$
.e$$$$$$$"="$f",c,3eee$$$$$$$$P $$$P'd$$$$"..::.."?$%
4d$$$P d$$$dF.d$$$$$$$$$$$$$$$$f $$$ d$$$" :::::::::.
$$$$$$ d$$$$$ $$$$$$$$$$$$$$$$$$ J$$",$$$'.::::::::::::
"$$$$$$ ?$$$$ d$$$$$$$$$$$$$$$P".dP'e$$$$':::::::::::::::
4$$$$$$c $$$$b`$$$$$$$$$$$P"",e$$",$$$$$' ::::::::::::::::
' ?"?$$$b."$$$$.?$$$$$$P".e$$$$F,d$$$$$F ::::::::::::::::::
"?$$bc."$b.$$$$F z$$P?$$",$$$$$$$ ::::::::::::::::::::
`"$$c"?$$$".$$$)e$$F,$$$$$$$' ::::::::::::::::::::
':. "$b...d$$P4$$$",$$$$$$$" :::::::::::::::::::::
':::: "$$$$$".,"".d$$$$$$$F ::::::::::::::::::::::
:::: be."".d$$$4$$$$$$$$F :::::::::::::::::::::::
:::: "??$$$$$$$$$$?$P" :::::::::::::::::::::::::
:::::: ?$$$$$$$$f .::::::::::::::::::::::::::::
:::::::`"????"".::::::::::::::::::::::::::::::