bartlett/phpunit-loggertestlistener

适用于兼容PSR-3日志记录器的PHPUnit测试套件监听器

2.2.0 2021-09-03 07:49 UTC

This package is auto-updated.

Last update: 2024-09-06 22:11:50 UTC


README

适用于兼容PSR-3日志记录器的PHPUnit测试套件监听器

Latest Stable Version Minimum PHP Version

目标是为PHPUnit提供一个标准的监听器,该监听器能够将单元测试结果发送到任何PSR-3兼容的日志记录器。

该监听器实现了PHPUnit\Framework\TestListener接口,并使用以下日志级别/事件映射。

错误

- `addError()`, when an error occurred
- `addFailure()`, when a failure occured

警告

- `addWarning()`, on warning test
- `addIncompleteTest()`, on incomplete test
- `addRiskyTest()`, on risky test
- `addSkippedTest()`, when a test was skipped

信息

- `startTest()`, when a test started
- `endTest()`, when a test ended

通知

- `startTestSuite()`, when a test suite started
- `endTestSuite()`, when a test suite ended

安装

重要:为了演示目的,使用了Growl处理器和AdvancedFilter处理器,但它们目前还不是GitHub或Packagist版本。

composer require bartlett/phpunit-loggertestlistener

与基本PSR-3日志记录器一起使用

我们将使用一个非常基本的PSR-3日志记录器进行第一步。假设我们有以下实现。

<?php

use Psr\Log\AbstractLogger;

class YourLogger extends AbstractLogger
{
    private $channel;

    public function __construct($name = 'YourLoggerChannel')
    {
        $this->channel = $name;
    }

    public function log($level, $message, array $context = array())
    {
        error_log(
            sprintf(
                '%s.%s: %s',
                $this->channel,
                strtoupper($level),
                $this->interpolate($message, $context)
            )
        );
    }

    protected function interpolate($message, array $context = array())
    {
        // build a replacement array with braces around the context keys
        $replace = array();
        foreach ($context as $key => $val) {
            if (is_scalar($val)) {
                $replace['{' . $key . '}'] = $val;
            }
        }

        // interpolate replacement values into the message and return
        return strtr($message, $replace);
    }
}

在您的phpunit.xml配置文件中添加Bartlett\LoggerTestListener测试监听器,使用我们的基本PSR-3日志记录器(YourLogger)。

使用您日志记录器的默认行为

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
    <listeners>
        <listener class="Bartlett\LoggerTestListener">
            <arguments>
                <object class="YourLogger" />
            </arguments>
        </listener>
    </listeners>
</phpunit>

我们可以将通道名称(从默认的YourLoggerChannel更改为值YourPSR3Logger)更改如下

配置日志记录器的通道名称

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
    <listeners>
        <listener class="Bartlett\LoggerTestListener">
            <arguments>
                <object class="YourLogger">
                    <arguments>
                        <string>YourPSR3Logger</string>
                    </arguments>
                </object>
            </arguments>
        </listener>
    </listeners>
</phpunit>

如果您想有更高级的日志记录策略,我建议您查看著名的Monolog PHP库。

与Monolog一起使用

没有处理器(然后默认输出将发送到STDERR),我们可以有如下配置,将日志记录器通道名称设置为YourMonologChannel

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
    <listeners>
        <listener class="Bartlett\LoggerTestListener">
            <arguments>
                <object class="Monolog\Logger">
                    <arguments>
                        <string>YourMonologChannel</string>
                    </arguments>
                </object>
            </arguments>
        </listener>
    </listeners>
</phpunit>

添加一些处理器,使用基本的Monolog日志记录策略(仅按级别过滤)。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
    <listeners>
        <listener class="Bartlett\LoggerTestListener">
            <arguments>
                <object class="Monolog\Logger">
                    <arguments>
                        <string>YourMonologChannel</string>
                        <array>
                            <element>
                                <object class="Monolog\Handler\StreamHandler">
                                    <arguments>
                                        <string>/var/logs/monolog.log</string>
                                    </arguments>
                                </object>
                            </element>
                            <element>
                                <object class="Bartlett\GrowlHandler">
                                    <arguments>
                                        <array></array>
                                        <integer>250</integer> <!-- NOTICE -->
                                    </arguments>
                                </object>
                            </element>
                        </array>
                    </arguments>
                </object>
            </arguments>
        </listener>
    </listeners>
</phpunit>

警告:当使用桌面通知(如growl)或由Pushover提供的移动通知时,您可能不希望接收所有日志记录,只想接收最重要的记录(错误、失败、测试套件结束)。

实际上Monolog无法做到这一点。因此,这是Pull Request添加过滤功能的原因。它现在作为一个独立包提供。请参阅Monolog Wiki页面和CallbackFilterHandler项目的页面

现在创建一个预先定义的日志记录器,其中包括我们想要的全部处理器和每个处理器的过滤规则。

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

use Bartlett\Monolog\Handler\GrowlHandler;
use Bartlett\Monolog\Handler\CallbackFilterHandler;

class YourMonolog extends Logger
{
    public function __construct($name = 'PHPUnit')
    {
        $filter1 = function($record, $handlerLevel) {
            if ($record['level'] < $handlerLevel) {
                return false;
            }
            if ($record['level'] > $handlerLevel) {
                return true;
            }
            return (
                preg_match('/^TestSuite(.*)ended\./', $record['message']) === 1
                and
                $record['level'] == $handlerLevel
            );
        };

        $stream = new StreamHandler('/var/logs/monolog.log');

        $handlers = [$stream];

        try {
            $growl = new GrowlHandler(array(), Logger::NOTICE);

            $filterGrowl = new CallbackFilterHandler(
                $growl,
                array($filter1)
            );
            $handlers[] = $filterGrowl;

        } catch (\Exception $e) {
            // Growl client is probably not started
            echo $e->getMessage(), PHP_EOL, PHP_EOL;
        }

        parent::__construct($name, $handlers);
    }
}

当然,我们像这样声明我们的新监听器

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
    <listeners>
        <listener class="Bartlett\LoggerTestListener">
            <arguments>
                <object class="YourMonolog" />
            </arguments>
        </listener>
    </listeners>
</phpunit>

我们将通过StreamHandler记录所有PHPUnit日志消息,并通过GrowlHandler(请参阅带有回调$filter1的过滤规则)仅记录重要通知。

运行测试套件示例

phpunit -c examples/phpunit.monolog.xml

您将得到类似以下内容

PHPUnit 7.5.1 by Sebastian Bergmann and contributors.

IRSF....F                                                           9 / 9 (100%)

Time: 79 ms, Memory: 10.00MB

There were 2 failures:

1) Your\Name_Space\YourTestSuite::testFailure
Failed asserting that an array is empty.

/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:31

2) Your\Name_Space\YourTestSuite::testDataProvider with data set #3 (1, 1, 3)
Failed asserting that 2 matches expected 3.

/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:44

--

There was 1 risky test:

1) Your\Name_Space\YourTestSuite::testRisky
This test did not perform any assertions

/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:20

FAILURES!
Tests: 9, Assertions: 7, Failures: 2, Skipped: 1, Incomplete: 1, Risky: 1.

带有Monolog Stream处理器的测试套件结果

[2018-12-30 11:00:19] PHPUnit.NOTICE: TestSuite 'Demo Test Suite' started with 9 tests. {"suiteName":"Demo Test Suite","testCount":9,"operation":"startTestSuite"} []
[2018-12-30 11:00:19] PHPUnit.NOTICE: TestSuite 'Your\Name_Space\YourTestSuite' started with 9 tests. {"suiteName":"Your\\Name_Space\\YourTestSuite","testCount":9,"operation":"startTestSuite"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testIncomplete' started. {"testName":"testIncomplete","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testIncomplete"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testIncomplete","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.WARNING: Test 'testIncomplete' is incomplete. {"testName":"testIncomplete","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testIncomplete"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testIncomplete","operation":"addIncompleteTest","reason":"This test has not been implemented yet.","trace":"/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:16\n"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testIncomplete' ended. {"testName":"testIncomplete","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testIncomplete"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testIncomplete","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testRisky' started. {"testName":"testRisky","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testRisky"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testRisky","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.WARNING: Test 'testRisky' is risky. {"testName":"testRisky","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testRisky"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testRisky","operation":"addRiskyTest","reason":"This test did not perform any assertions\n\n/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:20","trace":""} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testRisky' ended. {"testName":"testRisky","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testRisky"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testRisky","operation":"endTest","output":"","assertionCount":0} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testSkipped' started. {"testName":"testSkipped","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testSkipped"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testSkipped","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.WARNING: Test 'testSkipped' has been skipped. {"testName":"testSkipped","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testSkipped"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testSkipped","operation":"addSkippedTest","reason":"This test was skipped for any reason.","trace":"/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:26\n"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testSkipped' ended. {"testName":"testSkipped","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testSkipped"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testSkipped","operation":"endTest","output":"","assertionCount":0} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testFailure' started. {"testName":"testFailure","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testFailure"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testFailure","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.ERROR: Test 'testFailure' failed. {"testName":"testFailure","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testFailure"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testFailure","operation":"addFailure","reason":"Failed asserting that an array is empty.","trace":"/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:31\n"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testFailure' ended. {"testName":"testFailure","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testFailure"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testFailure","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testPass' started. {"testName":"testPass","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testPass"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testPass","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testPass' ended. {"testName":"testPass","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testPass"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testPass","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.NOTICE: TestSuite 'Your\Name_Space\YourTestSuite::testDataProvider' started with 4 tests. {"suiteName":"Your\\Name_Space\\YourTestSuite::testDataProvider","testCount":4,"operation":"startTestSuite"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #0' started. {"testName":"testDataProvider with data set #0","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #0"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #0 (0, 0, 0)","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #0' ended. {"testName":"testDataProvider with data set #0","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #0"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #0 (0, 0, 0)","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #1' started. {"testName":"testDataProvider with data set #1","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #1"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #1 (0, 1, 1)","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #1' ended. {"testName":"testDataProvider with data set #1","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #1"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #1 (0, 1, 1)","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #2' started. {"testName":"testDataProvider with data set #2","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #2"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #2 (1, 0, 1)","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #2' ended. {"testName":"testDataProvider with data set #2","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #2"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #2 (1, 0, 1)","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #3' started. {"testName":"testDataProvider with data set #3","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #3"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #3 (1, 1, 3)","operation":"startTest"} []
[2018-12-30 11:00:19] PHPUnit.ERROR: Test 'testDataProvider with data set #3' failed. {"testName":"testDataProvider with data set #3","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #3"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #3 (1, 1, 3)","operation":"addFailure","reason":"Failed asserting that 2 matches expected 3.","trace":"/shared/httpd/phpunit-LoggerTestListener/examples/testSuite.php:44\n"} []
[2018-12-30 11:00:19] PHPUnit.INFO: Test 'testDataProvider with data set #3' ended. {"testName":"testDataProvider with data set #3","testDescriptionArr":["Your\\Name_Space\\YourTestSuite","testDataProvider with data set #3"],"testDescriptionStr":"Your\\Name_Space\\YourTestSuite::testDataProvider with data set #3 (1, 1, 3)","operation":"endTest","output":"","assertionCount":1} []
[2018-12-30 11:00:19] PHPUnit.NOTICE: TestSuite 'Your\Name_Space\YourTestSuite::testDataProvider' ended. {"suiteName":"Your\\Name_Space\\YourTestSuite::testDataProvider","testCount":3,"assertionCount":4,"failureCount":1,"errorCount":0,"incompleteCount":0,"skipCount":0,"riskyCount":0,"operation":"endTestSuite"} []
[2018-12-30 11:00:19] PHPUnit.NOTICE: TestSuite 'Your\Name_Space\YourTestSuite' ended. {"suiteName":"Your\\Name_Space\\YourTestSuite","testCount":1,"assertionCount":3,"failureCount":1,"errorCount":0,"incompleteCount":1,"skipCount":1,"riskyCount":1,"operation":"endTestSuite"} []
[2018-12-30 11:00:19] PHPUnit.NOTICE: TestSuite 'Demo Test Suite' ended. {"suiteName":"Demo Test Suite","testCount":4,"assertionCount":7,"failureCount":2,"errorCount":0,"incompleteCount":1,"skipCount":1,"riskyCount":1,"operation":"endTestSuite"} []

带有Growl处理器的测试套件结果

Growl Notifications

注意:由Growl for Windows(2.0.9和Smokestack显示)以及PHP GNTP库生成。

许可证

LoggerTestListener在BSD-3条款许可下授权 - 有关详细信息,请参阅LICENSE文件。