是否可以使用PHPUnit @depends而不在依赖用例之间调用tearDown和setUp?

svdrlsy4  于 2023-01-24  发布在  PHP
关注(0)|答案(5)|浏览(148)

例如,test1中的操作将数据存储在外部 *,然后test2会对这些数据执行Assert,但tearDown删除了该数据,从而中断了test2。无法从tearDown中删除缓存,因为其他测试依赖于它。此问题询问是否有方法跳过setUp/在依赖用例之间tearDown,同时保持@depends的功能(如果第一个测试失败而不是第二个测试失败,则跳过第二个测试)。

public function tearDown() {
    // delete cache
}

// verify the expected data was retrieved from an uncached source
public function test1() {
    $sut = new SystemUnderTest();
    $data = $sut->getDataAndCache();
    $this->assertEquals('expected', $data);
    return $sut;
}

// verify the expected data was cached
/** @depends test1 */
public function test2($sut) {
    $this->assertEquals('expected', $sut->getCache());
}
  • 我们将这些测试称为集成测试,因为它们与外部系统交互。
xmd2e60i

xmd2e60i1#

在设置方法中,您可以检查测试是否具有hasDependencies(),然后跳过设置程序:

public function setUp()
{
    if (!$this->hasDependencies()) {
        // do setup tasks 
    }
}
50pmv0ei

50pmv0ei2#

有几个选择。
第一种方法是将这两个测试分离到一个单独的测试类中,这样其他类中的tearDown就不会干扰。
在测试之后,你可能仍然想删除该高速缓存。当然,测试缓存删除可能是一个独立的步骤。但是PHPUnit也提供了两个静态方法,分别在测试类开始测试之前和类中的所有测试运行之后运行:setUpBeforeClass()tearDownAfterClass()(请参见http://phpunit.de/manual/3.7/en/fixtures.html)。
另一方面,最简单的解决方法是将两个测试方法合并到一个函数中,您已经遇到了一些麻烦,因为将函数命名为getDataANDCache违反了单一责任原则,因此将测试分离为两个函数没有什么好处。

ijnw1ujt

ijnw1ujt3#

下面是针对PHPUnit 9.5的一个破解方法:

protected function setUp(): void
    {
        parent::setUp()

        // prevent from running for tests with @depends
        if (!empty($this->requires())) { 
            return;
        }

        // ...
    }

它对问题的要求起作用。

**然而,**我说过这是一个黑客,所以请记住:

  • tearDown仍在运行-并且它破坏测试对象示例(a.k.a. $this),回滚所有事务(如果您使用use DatabaseTransactions;),等等。
  • 如果你给$this分配了公共变量-它们将消失!
  • parent::setUp()(如果您使用Laravel或类似的框架)引导应用程序,这就是为什么您很可能仍然需要像示例中那样每次都调用它的原因。

所以简而言之,这不是一个好主意最有可能。
也许可以考虑使用像PestPHP这样的PHPUnit Package 器来 Package 像这样的语法糖,我只是希望它经过更多的时间考验,不太可能在十年的时间里被放弃...

lokaqttq

lokaqttq4#

我的一个想法是使用一个静态字段,比如is_depends,在test1中设置为true,在test2setUp中设置为false,tearDown在运行之前检查is_depends的值。

private static is_depends;

public function setUp() {
    if (self::$is_depends) return;
    // do setup that shouldn't be done between dependencies
}

public function tearDown() {
    if (self::$is_depends) return;
    // delete cache
}

// verify the expected data was retrieved from an uncached source
public function test1() {
    $sut = new SystemUnderTest();
    $data = $sut->getDataAndCache();
    $this->assertEquals('expected', $data);
    self::$is_depends = true;
    return $sut;
}

// verify the expected data was cached
/** @depends test1 */
public function test2($sut) {
    $this->assertEquals('expected', $sut->getCache());
    self::$is_depends = false;
}

有更好的办法吗?

iezvtpos

iezvtpos5#

另一个选择是在两个测试中执行大部分的arrange和act步骤,这样就不需要维护test1和test2之间的外部状态,如果test1失败,@depends注解仍然会导致test2被跳过,如果arrange和act步骤更复杂,可以将它们提取到一个单独的方法中,并由两个测试调用。
下面是更新后的test2方法的示例(使用原始问题中的test1):

// verify the expected data was cached
/** @depends test1 */
public function test2($sut) {
    $data = $sut->getDataAndCache();
    $this->assertEquals('expected', $sut->getCache());
}

相关问题