【问题标题】:PHPUnit - Check if an array contains an object of a specific typePHPUnit - 检查数组是否包含特定类型的对象
【发布时间】:2015-04-02 09:23:57
【问题描述】:

在 PHPUnit 中进行单元测试时,我需要检查一个数组是否至少包含一个特定类型的对象。

这是我正在寻找的一个简单的例子

$obj_1 = new Type1;
$obj_2 = new Type2; 

$container = array( $obj_1, $obj_2 );

// some logic and array manipulation here

// need something like this
$this->assertArrayHasObjectOfClass( 'Type1', $container );

显然我可以使用自定义代码来做到这一点,但是否有任何断言(或它们的组合)允许我这样做?

我需要在多个测试中多次这样做,如果我需要的断言不存在,我该如何扩展 PHPUnit 断言集?

编辑:具有特征的自定义解决方案

按照 Vail 的建议,我想出了一个使用特征的自定义解决方案。这是一个简化版。

// trait code
trait CustomAssertTrait
{
    public function assertArrayHasObjectOfType( $type, $array, $message = '' ) {

        $found = false;

        foreach( $array as $obj ) {
            if( get_class( $obj ) === $type ) {
                $found = true;
                break;
            }
        }

        $this->assertTrue( $found, $message );

    }
}

// test code
class CustomTest extends PHPUnit_Framework_TestCase {
   use CustomAssertTrait;

   // test methods... 
}

【问题讨论】:

  • 如果您能提供一个您想要实现的最小工作示例,那就太好了。
  • 如果发现你可能想break 退出循环。
  • 您可以尝试将assertInstanceOf() 设为example
  • 我不认为我可以,因为我必须将它放在 for/foreach 循环中,如果第一次出现的不是我要查找的类,则执行将停止。跨度>

标签: php arrays unit-testing phpunit


【解决方案1】:

如果您只检查一个对象,请使用方法 assertContains() 并将数组或 Traversable 作为第二个参数。但是这里的对象必须具有与您要查找的对象相同的属性(例如 id、title 等) 例如。

$obj_x = new Type1;
$this->assertContains($obj_x, $container);

如果数组或 Traversable 中的所有对象都具有相同的祖先或接口,则可以使用方法 assertContainsOnlyInstancesOf() ex.

$this->assertContainsOnlyInstancesOf(Type1Type2Interface::class, $container);

https://phpunit.de/manual/5.7/en/appendixes.assertions.html#appendixes.assertions.assertContainsOnlyInstancesOf

【讨论】:

    【解决方案2】:

    我不认为对此有断言。您将需要编写一些自定义代码。

    关于extendig PHPUnit 断言,您可以使用自己的断言方法创建特征并将其添加到特定测试中。

    或者看看这个https://phpunit.de/manual/current/en/extending-phpunit.html

    【讨论】:

      【解决方案3】:

      与您的解决方案类似:

      $found = (bool)array_filter($array, function($v) use ($type) {
                                              return get_class($v) === $type;
                                          });
      

      【讨论】:

      • 这是一个智能的解决方案,可以将所有内容集中在一条线上。但我认为我的解决方案与您的建议(我在 foreach 循环中添加了一个中断)它的内存更安全。此外,我不知道如何在 array_filter 的情况下在低级别实现 PHP 闭包。我的意思是,闭包是在每次循环时创建的,还是创建一次然后被所有迭代使用?
      • 创建一次。 array_filter 是高效 C 代码的小型包装器。它比没有提前退出的任何 php 循环更快或一样快。
      • 数组是第一个参数而不是回调
      【解决方案4】:

      回答,因为我也在寻找信息并在挖掘方法列表时发现:

      • phpunit 版本:9.5.13
      • 方法名:assertContainsOnly
      • 示例:$this->assertContainsOnly(Dto::class, $this->provider->provide());

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-12
        • 2022-08-18
        • 2020-06-07
        • 2012-10-17
        • 2016-02-04
        • 1970-01-01
        相关资源
        最近更新 更多