phpunit:避免打印很长的输出
Posted
技术标签:
【中文标题】phpunit:避免打印很长的输出【英文标题】:phpunit: Avoid printing very long output 【发布时间】:2020-04-29 09:26:39 【问题描述】:我有一个 phpUnit 测试,它检查渲染的 html 输出不包含某个字符串,我使用:
public function testSomething()
$htmlOutput = ...;
self::assertDoesNotMatchRegularExpression(
'/...pattern to detect a certain error.../',
$htmlOutput,
'HTML response contained a certain error',
);
当测试失败时,PHPUnit 会打印一个超长的输出:
There was 1 failure:
1) MyTest::testSomething
HTML response contained a certain error
Failed asserting that '<!DOCTYPE html>\r\n
<html lang="en">\r\n
<head>\r\n
...
... hundreds and hundreds of lines
....
</body>\r\n
</html>' does not match PCRE pattern "/...pattern to detect a certain error.../".
这很烦人,因为所有重要信息现在都在我的终端中向上滚动,无法触及,这是失败测试的名称和实际消息“HTML 响应包含某个错误”。当然,确切的字符串对于找出问题所在可能很重要,但在一半的情况下,消息已经足够好了。
这里推荐的方法是什么?
【问题讨论】:
【参考方案1】:恐怕使用assertDoesNotMatchRegularExpression()
时就是这个样子。话虽如此,我建议不要使用正则表达式来验证 HTML 或 XML。改用使用 CSS 选择器或 XPath 表达式的专用断言。
【讨论】:
您对不使用 HTML 的正则表达式是绝对正确的,我将寻找更好的替代方案来解析 HTML/XML(并因此断言其有效结构)。然而,并非我的所有输出都是 HTML 或 XML,但我找到了一个替代方案,我将很快发布作为附加答案。【参考方案2】:正如 Sebastian Bergmann 所指出的,通常 HTML 和 XML 验证不应该使用正则表达式来完成。我发现 PHP 的带有 xpath 查询的 XML 解析器很有用。此外,框架通常包含有用的 PHPUnit 扩展(例如 symfony)。
也就是说,我确实找到了一个即使对于非 HTML 内容也能很好地工作的解决方案,例如长纯文本输出。它涉及编写自定义 PHPUnit 约束:
use PHPUnit\Framework\Constraint\Constraint;
/**
* Class RegularExpressionForLongString is a variant of PHPUnit's RegularExpression that
* does not print the entire string on failure, which makes it useful for testing very
* long strings. Instead it prints the snippet where the regex first matched.
*/
class RegularExpressionForLongString extends Constraint
/**
* Maximum length to print
*/
private const MAX_LENGTH = 127;
/**
* @var string
*/
private $pattern;
/**
* @var array|null
*/
private $lastMatch = null;
/**
* RegularExpressionForLongString constructor.
*
* @param string $pattern
*/
public function __construct(string $pattern)
$this->pattern = $pattern;
/**
* @inheritDoc
*/
public function toString(): string
return sprintf(
'matches PCRE pattern "%s"',
$this->pattern
);
/**
* @inheritDoc
*/
protected function matches($other): bool
return preg_match($this->pattern, $other, $this->lastMatch, PREG_OFFSET_CAPTURE) > 0;
/**
* @inheritDoc
*/
protected function failureDescription($other): string
if (!is_string($other))
return parent::failureDescription($other);
$strlen = strlen($other);
$from = $this->lastMatch[0][1];
$to = $from + strlen($this->lastMatch[0][0]);
$context = max(0, intdiv(self::MAX_LENGTH - ($to - $from), 2));
$from -= $context;
$to += $context;
if ($from <= 0)
$from = 0;
$prefix = '';
else
$prefix = "\u2026";
if ($to >= $strlen)
$to = $strlen;
$suffix = '';
else
$suffix = "\u2026";
$substr = substr($other, $from, $to - $from);
return $prefix . $this->exporter()->export($substr) . $suffix . ' ' . $this->toString();
然后在一个新的基类中进行测试:
use PHPUnit\Framework\Constraint\LogicalNot;
/**
* Class MyTestCase
*/
class MyTestCase extends TestCase
/**
* Asserts that a string does not match a given regular expression. But don't be so verbose
* about it.
*
* @param string $pattern
* @param string $string
* @param string $message
*/
public static function assertDoesNotMatchRegularExpressionForLongString(string $pattern, string $string, string $message = ''): void
static::assertThat(
$string,
new LogicalNot(new RegularExpressionForLongString($pattern)),
$message,
);
这是一个如何使用它的示例:
self::assertDoesNotMatchRegularExpressionForLongString('/\[A-Z_]+\/', $content, "Response contains placeholders that weren't substituted");
这是失败的示例输出:
There was 1 failure:
1) <namespace>\SomeClassTest::testFunc
Response contains placeholders that weren't substituted
Failed asserting that …'re will be context printed here\r\n
CLIENT_FIRST_NAME\r\n
Some other text here.\r\n
'… does not match PCRE pattern "/\[A-Z_]+\/".
【讨论】:
以上是关于phpunit:避免打印很长的输出的主要内容,如果未能解决你的问题,请参考以下文章
markdown [漂亮的打印机] Phpunit Pretty Printer安装#phpunit #laravel #prettyprinter #intsall #php
Laravel 5.3 - 避免在 phpunit 测试中发送松弛通知