antonioprimera/phpunit-custom-assertions

自定义测试断言,目前尚未包含在PHPUnit中。

v1.0 2021-12-16 15:51 UTC

This package is auto-updated.

Last update: 2024-09-16 21:41:29 UTC


README

如果你是一个严肃的TDD爱好者,你可能会遇到需要特殊断言方法的情况。

这是一个我尝试收集一些对PHPUnit测试有用的自定义断言的包。此包依赖于Laravel的Illuminate\SupportIlluminate\Contracts,主要面向Laravel测试,但也应在裸骨PHPUnit环境中运行良好。

目前,以下断言类别得到了覆盖

  • 文件内容断言
  • 文件和文件夹存在性
  • 列表比较(数组、迭代器、Laravel集合等)

安装

通过Composer导入

composer require --dev antonioprimera/phpunit-custom-assertions

然后在你的测试用例中仅使用trait AntonioPrimera\Testing\CustomAssertions

使用方法

在测试用例中包含trait AntonioPrimera\Testing\CustomAssertions后,你可以在测试中直接调用此包中包含的任何断言方法。

以下是一个简短的例子,涵盖了此包中的大多数断言

namespace AntonioPrimera\Testing\Tests\Unit;

use AntonioPrimera\Testing\CustomAssertions;
use PHPUnit\Framework\TestCase;

class FileAssertionsTest extends TestCase
{
	use CustomAssertions;
	
	/** @test */
	public function it_can_do_any_of_the_implemented_assertions()
	{
	    //you can call any of the assertions as instance methods, functions or static methods
	    $this->assertFileContains('CustomAssertions', __FILE__);
	    assertFileContains(['namespace', 'use'], __FILE__);
	    static::assertFileContentsEquals('abc', __FILE__, function($str) { return 'abc'; });
	    
	    //compares two lists
	    $this->assertListsEqual(['a', 1, [true, null, collect([0, 5])]], [[null, true, [5,0]], 1,'a']);
	    
	    //the following assertion is expected to fail, containing the messages given as parameters
	    $this->expectAssertionToFail(__FILE__ . '.js');
	    $this->assertFilesExist([__FILE__, __FILE__ . '.js']);
	}
}

由于断言是基于基本的PHPUnit框架约束编写的,因此所有断言都可以作为静态方法调用

static::assertFileContains($string, $filePath);

作为实例方法

$this->assertFileContains($string, $filePath);

或作为函数

assertFileContains($string, $filePath);

可用的断言

文件和文件夹

assertFileContains(string | array $subString, string $filePath, [callable $processor])

此断言检查给定路径的文件$filePath是否包含字符串$subString

为了方便使用,你可以通过提供一个字符串数组作为第一个参数($substring),来检查文件是否包含多个字符串。

$this->assertFileContains('namespace', $filePath);
$this->assertFileContains(['namespace', 'class'], $filePath);

如果你想处理文件内容和字符串,在检查之前,你可以提供可调用的字符串处理器(一个函数或方法)作为第三个参数。可调用的接收一个字符串作为其参数(文件内容和要比较的每个字符串),然后返回一个处理后的字符串,该字符串将用于实际的比较。

例如,如果你想比较之前移除所有空白字符(空格、制表符、换行符),你可以使用以下示例中的函数。这在不关心文件内容格式的情况下非常有用。

$this->assertFileContains(
    'namespace App\\Models; class User{ }',
    $userModelFilePath,
    function($str) {
        return str_replace([' ', "\t", "\n"], '', $str);
    } 
);

因为这个函数非常有用,我将其添加到了一个公共静态方法removeWhiteSpaces中,这样你就不必每次都自己编写它。你可以像这样使用它

assertFileContains($substr, $filePath, static::removeWhiteSpaces());

assertFileContentsEquals(string $expected, string $path, [callable $processor])

此断言与assertFileContains(...)类似,但只能接收单个字符串作为第一个参数,并将检查该字符串是否与文件的全部内容完全相同。也可以提供一个处理器函数/可调用项,就像前面的断言一样。

assertFilesExist(string | array $filePaths)

此断言与原始文件存在断言类似,但允许你提供一个或多个文件路径(字符串或数组),在失败的情况下,它将告诉你哪些文件不存在。

assertFoldersExist(string | array $folderPaths)

这与 assertDirectoryExists 类似,但断言有一个更好的名称 文件夹 而不是 目录(认真地说,谁会叫它们目录?)允许你提供一个或多个文件夹路径(字符串 | 数组),如果失败,它将告诉你哪些文件夹不存在。

列表 / 数组 / 集合

assertListsEqual($expected, $actual, [bool $strict = false])

此断言将尽力检查实际列表是否与预期列表相同。

$expected$actual 参数可以是任何可迭代类型——因此术语列表是通用的。

  • 数组
  • 任何可迭代的对象(请参阅 php 文档
  • 实现 Illuminate\Contracts\Support 的对象(例如 Laravel 集合)

这会尝试比较关联列表(具有字符串键)、索引列表(具有数字键)以及混合列表(具有字符串和整数键),忽略索引项出现的顺序。

此断言还会比较深层/嵌套列表——这对于嵌套索引列表尤其具有挑战性。

要进行严格比较,将 $strict 标志设置为 true。请注意,NULL 值将单独比较,因此它们必须与另一个 NULL 值匹配,无论 $strict 如何,但任何其他东西,如布尔值及其数值对应物 0 和 1,在非严格模式下将进行交叉匹配,可能提供错误的断言。

目前有几个注意事项(它们可以解决,但有人需要它们吗?这值得努力吗?)

  1. 除了列表(集合/可迭代列表实例)和 Eloquent 模型(这是 Laravel 的事情)之外的对象无法正确比较
    1. 在严格模式下,对象必须是同一实例的引用(比较 spl_ids)
    2. 在非严格模式下,仅比较对象类
  2. 可调用项无法比较——只有实际列表包含相同数量的可调用项
  3. 资源无法比较——只有实际列表包含相同数量的资源
$this->assertListsEqual(['a', 1, [true, null, collect([0, 5])]], [[null, true, [5, 0]], 1, 'a']);

//this will succeed in non-strict mode, but will fail in strict mode
$this->assertListsEqual(['a', 1, [1, null, collect([0, 5])]], [[null, true, [5, false]], 1, 'a']);

assertArraysEqual($expected, $actual, [bool $strict = false])

这使用之前的(assertListEqual)断言,但检查两个列表是否实际是数组。

辅助工具

expectAssertionToFail(...$messages)

此辅助工具的工作方式类似于断言,并期望下一个(或下一个之一)断言失败。如果提供了消息或消息列表,它还会检查失败消息是否包含给定的字符串。

由于 PHPUnit 的工作方式,测试在第一个失败的断言后结束,因此你在失败断言之后编写的任何断言都将被忽略(有绕过方法,但这是一个很好的挑战你的创造力或 StackOverflow 搜索技能的机会)。话虽如此,建议在测试结束时使用此方法,在失败断言之前。

例如:

public function test_that_something_does_not_work()
{
    //successful assertion
    $this->assertFoldersExist([__DIR__, app_path(), resource_path()]);
    
    //expect the next assertion to fail and the failure message to contain the 2 missing folder paths
    $this->expectAssertionToFail(app_path('random/folder'), resource_path('nix/da'));
    //failing assertion
    $this->assertFoldersExist([__DIR__, app_path('random/folder'), resource_path('nix/da')]);
}

测试

目前:18 个测试,65 个断言。

此包经过彻底测试,运行顺利。

未来开发 / 贡献 / 支持

我计划在我为我的项目开发新断言后立即在这里添加它们。如果您喜欢这个包,您也可以查看我的其他开源包(大多是针对 Laravel 的)。

此包是开源的,因此欢迎任何贡献。如果您想做出改进、新功能或重大更改的贡献,请在投入任何工作之前联系我,并告诉我您的需求以及您计划做出的更改。