提问人:klutt 提问时间:9/2/2023 最后编辑:klutt 更新时间:9/5/2023 访问量:84
有没有一种简单的方法可以反转测试或测试组?
Is there a simple way to invert a test or test group?
问:
假设您编写了一个失败的测试来利用错误。您希望将其推送到上游,然后创建一个关于修复代码以便测试通过的故事。但是,运行所有测试的管道会阻止这种情况。
我提出了一个解决方案:将测试添加到一个组,然后编辑以排除该组,使管道跳过该测试。解决 bug 后,只需从排除的组中删除测试即可。phpunit.xml
这里的一个问题是最后一步可能会被遗忘。无论测试是否通过,管道都将通过。
我认为解决这个问题的一个方法是,我们不希望它失败,而不是排除测试。有没有办法以这样一种方式进行配置,即属于特定组的所有测试都至少有一个断言失败?我查看了文档,但没有找到任何东西。注释也是如此。一个解决方案是,如果有一个像这样的注释,但我也没有找到类似的东西。phpunit.xml
@expectToFail
也许反转测试不是正确的方法。但是要写一个我想做的事情的简短总结,而不假设任何最好的方法。
- 我应该能够编写一个失败的测试,该测试不得使管道失败。
- 如果测试测试的代码被修改,以便 (1) 中的测试通过而不对项目进行任何其他更改,则管道必须失败。
- 当 (2) 发生时,必须有一种非常简单的方法来反转它,以便管道在测试失败时必须失败,并且在测试通过时不得失败。
如果可能的话,我希望在不更改测试代码的情况下执行此操作,例如手动更改为 .assertFalse
assertTrue
我可能会补充一点,它是 bitbucket 管道
澄清一下,这基本上是我想要的。假设我们有以下代码:
class Foo {
// Function with obvious bug
public function sum(a, b) {
return a-b;
}
}
显然,该函数有一个错误。所以我们写了一个单元测试:sum
class FooTest {
/**
* @test
*/
public function bugExploit() {
$foo = new Foo();
static::assertEqual(8, $foo->sum(3,5));
}
}
现在我们提交这个测试并推送它。管道应在此推送后通过,前提是它之前通过。然后我们写一个关于解决这个错误的故事。
是时候下一位开发人员了。他们拿起了“修改 Foo:sum 以便测试 FooTest::bugExploit 通过”的故事。阅读此内容后,开发人员将更改为 ,而不进行其他任何更改。他们推送代码。现在我预计管道会失败。return a-b
return a+b
一个可行的解决方案是,如果存在一个名为注解的注解,第一个开发人员将其添加到文档注释中,以预期测试会失败,然后第二个开发人员删除该行。@fail
答:
更新
不确定你要做什么会被认为是一个好的做法,顺便说一句,我会试着逐点回答你:
- 这种行为可以通过多种方式获得:使用 、 使用(和排除)等或使用 try/catch 语句。请注意,如果对多个断言使用单个 try/catch,则第一次失败将阻止整个测试。为了确保测试所有断言,您需要进行多个 try/catch 语句:
markTestIncomplete()
groups/levels/paths
function testPassWithFailures() {
$failures = [];
try {
// First assertion
$this->assertTrue(false);
} catch(PHPUnit_Framework_ExpectationFailedException $e) {
$failures[] = $e->getMessage();
}
try {
// Second assertion
$this->assertTrue(false);
} catch(\PHPUnit\Framework\ExpectationFailedException $e) {
$failures[] = $e->getMessage();
}
// ...
if(!empty($failures))
{
// Here you can put your logic and decide if failures should make the test fail
// or pass
// Throw a new exception to make it fail
throw new \PHPUnit\Framework\ExpectationFailedException (...);
}
}
正如你所看到的,这是一种不太好的方法,但也许它可以帮助你思考不同的解决方案。
2/3. 这是最难的部分。“不对项目进行任何其他更改”是什么意思?您只想考虑对当前测试文件进行编辑吗?执行变基或合并时会发生什么情况?假设您已经知道此方法的问题,您可以尝试以下特定方法:
首先,创建一个基于文件后缀(例如。testsuite
TestDemoIncomplete.php)
<testsuites>
<testsuite name="incomplete-tests">
<directory suffix="Incomplete.php">test</directory>
</testsuite>
</testsuites>
然后,您可以创建一个脚本来运行测试并执行 ,以了解哪些文件被修改,然后在 上运行。然后,您必须在脚本中加入一些逻辑,以便在测试通过时删除“不完整”后缀。这样,当您的测试首次通过时,其“不完整”标记将被删除,这将被视为标准测试。git diff
phpunit
incomplete-tests
您可以构建此脚本以在 Git Hooks 上运行或直接在管道中运行(但是,由于您将更改文件名,因此可能需要新的提交)。
我不是在向你推荐一个开箱即用的解决方案,我是试图给你一些关于你想要实现的目标的提示。在我看来,这是一种糟糕的方法,我会尝试找到一种解决方案,因为它适用于这种情况(此外,您可以解析脚本的输出以获取警告,然后使用此信息来阻止您的管道或简单地警告开发人员)。markTestIncomplete
旧答案
您可以将测试标记为未完成 (https://docs.phpunit.de/en/10.3/writing-tests-for-phpunit.html#incomplete-tests):
$this->markTestIncomplete(
'This test has not been implemented yet.',
);
测试将通过,但输出中将生成警告:
...
There was 1 incomplete test:
1) WorkInProgressTest::testSomething
This test has not been implemented yet.
/path/to/tests/WorkInProgressTest.php:12
OK, but there were issues!
Tests: 1, Assertions: 1, Incomplete: 1.
评论
markTestIncomplete
更新
这个答案不起作用。我正在研究解决方案。问题在于,只要至少一个标记的测试失败,管道就会通过。我希望它要求它们都失败才能通过。@failing
老
我设法解决了它。
首先,我配置为排除带有注释的测试,正如我在问题中已经提到的。我用:phpunit.xml
@group failing
<groups>
<exclude>
<group>failing</group>
</exclude>
</groups>
然后,我在管道中复制了测试命令。它在表格上.我的想法是简单地否定返回代码。我尝试了几种在终端中工作的方法,但我从未让 bitbucket 管道理解否定。docker run testuser ./vendor/bin/phpunit
因此,我编辑了该项目,并添加了以下内容:Makefile
failing-tests:
! docker run testuser ./vendor/bin/phpunit --group failing
请注意命令前面的 。这就是魔力。!
在那之后,我只是简单地添加了make failing-tests
bitbucket-pipelines.yml
通过对表单的简单测试进行了尝试
class MyTest extends TestCase{
/**
* @test
* @failing
*/
public function aFailingTest(): void {
static::assertTrue(false);
}
}
由于注解,主测试套件忽略了此测试,并且管道通过了。当我更改为管道失败时。正是我想要的。assertTrue(true)
评论