toast/unit

针对 PHP7 的超级简单的单元测试

2.2.1 2022-07-07 12:37 UTC

README

Toast 是一个受 JavaScript 测试框架(如 Karma、Jasmine 等)启发的 PHP 超简单测试框架。

Toast 是因为对现有测试框架(在我们看来)过于庞大、复杂且难以设置而诞生的。有些还非常慢(比如 PHPUnit)。

特性

  • 非常 快速
  • 使用原生 PHP assert 进行断言
  • 使用 DocComments 进行特性描述
  • 相关测试的分组

安装

$ composer require --dev toast/unit

在项目的根目录中创建一个 Toast.json 配置文件。它应包含至少一个 "tests" 键,指向放置测试的目录。测试可以放在(子)目录中;Toast 会递归搜索。

可选地,配置可以包含一个 "bootstrap" 键,包含在运行之前要包含的文件数组。这些可以包含项目的设置(例如依赖注入逻辑)。

开启断言并配置它们在失败时抛出 AssertionError。请参阅 手册中的此部分;两个值都应该设置为 1

配置

将配置文件放在项目的根目录中(或在运行 Toast 时可选地指定它)。该文件支持 Kingconf 支持的所有格式;这里我们将使用 JSON。

示例配置文件

{
    "tests": "path/to/my/tests"
}

是的,就是这样 :)

使用方法

$ vendor/bin/toast

就是这样 :) 您可以可选地指定一个 --filter= 参数,包含一个正则表达式。在这种情况下,只有与文件名匹配的测试将被运行。过滤器不区分大小写,使用 "@" 作为分隔符。

其他可选标志包括

  • -v 用于详细模式
  • -o 用于输出模式(见下文)

编写测试

这再简单不过了!每个测试(组)都是一个 可调用 的。Toast 假设任何返回 Generator 的可调用项是一个组;其他可调用项是实际的测试。例如

<?php

/** Description of this group */
return function () : Generator {
    /** Test if true == true */
    yield function () {
        assert(true);
    };
};

您可以为每个测试添加尽可能多的断言,但通常最好将断言数量限制到尽可能少(最好是单个),并使用生成器对相关测试进行分组

<?php

return function () : Generator {
    $obj = new My\Thing\Under\Test;
    /** Test method foo */
    yield function () use ($obj) {
        assert($obj->foo());
    };
    /** Test method bar */
    yield function () use ($obj) {
        assert($obj->bar());
    };
};

嵌套可以深到适合您的项目。

设置

测试可调用项将与 $this 绑定的实际测试实例(Toast\Unit\Test 的一个实例)一起调用。这暴露了一个接受可调用项的 beforeEach 方法,在每组测试之前(嵌套组中的测试不继承它们)调用。可以多次调用 beforeEach

<?php

return function () : Generator {
    $this->beforeEach(function () {
        echo "1\n";
    });
    yield function () : Generator {
        $this->beforeEach(function () {
            echo "2\n";
        });
        yield function () { assert(true); };
    };
    yield function () {
        assert(true);
    };
};

在上面的示例中,由于 beforeEach 对两个顶级 yield 都是有效的,因此 "1" 将被输出两次。"2" 将只输出一次,因为它只适用于嵌套的 yield,而这个嵌套的 yield 对其父项一无所知。

您可以使用 beforeEach 来加载数据库固定值等。如何做取决于您。

清理

类似地,如果需要清理,有一个 afterEach 方法也以相同的方式工作。

这很显然,但是beforeEachafterEach只会应用于在相应调用之后被yield的测试。这是因为PHP在生成器内部会暂停执行。对于复杂的测试,在组中间添加before/after可调用对象可能有意义,但通常你只需将它们放在开始处。如果你发现自己需要在组中间添加它们,通常这意味着你应该将测试组拆分成更小的单元。

测试不仅仅是简单的断言

Toast假设成功的测试是一个通过的断言。但是,如果你需要测试是否抛出异常呢?很简单

<?php

//...
yield function () {
    $foo = new Foo;
    $e = null;
    try {
        $foo->bar();
    } catch (FooException $e) {
    }
    assert($e instanceof FooException);
};

Toast还假设测试不会产生输出。所以,要测试一个函数是否实际上确实产生输出,请使用输出缓冲。

<?php

//....
yield function () {
    ob_start();
    thisFunctionPrintsSomething();
    assert(ob_end_clean() == "Hello world!");
};

在调用Toast时,你可以选择指定-o参数来关闭此功能。这有助于开发,因为你可以更轻松地var_dump东西,直到你得到一个有效的测试。

检测Toast运行

Toast设置了一个环境变量TOAST,你的代码可以检查它,例如,知道你想要使用哪个数据库(开发或测试)

<?php

if (getenv("TOAST")) {
    $db = new PDO('mysql:test');
} else {
    $db = new PDO('mysql:dev');
}

还有一个(唯一的)TOAST_CLIENT设置,你可以用来识别特定的Toast运行。如果你测试的功能将某些东西存储在某个位置,并且你需要能够识别它,这将很有用。