【问题标题】:Testing Use of Class Optionally Included in Project测试项目中可选包含的类的使用
【发布时间】:2015-05-26 15:12:19
【问题描述】:

我有一个类似于以下内容的课程:

class Foo {

  /**
   * @var array|Bar
   */
  protected $source;

  public function __construct($source = []) {
    if (class_exists(Bar::class)) {
      $source = new Bar($source);
    }

    $this->source = $source;
  }

  public function getSource() {
    return $this->source;
  }

  // ...

}

Bar 来自一个单独的 PHP 包,这是composer.json 的suggest 部分中列出的可选依赖项。

我想在 phpspec 中为 getSource() 写两个单独的期望

function it_provides_array_source_by_default() {
  $this->getSource()->shouldBeArray();
}

function it_provides_bar_instance_when_available() {
  $this->getSource()->shouldReturnAnInstanceOf(Bar::class);
}

如果我的包的require-dev 包含包含Bar 的依赖项,我无法测试shouldBeArray()。

我不能嘲笑 Bar 喜欢:

function it_provides_bar_instance_when_available(Bar $bar) {
  $this->getSource()->shouldReturnAnInstanceOf(Bar::class);
}

因为我得到一个 phpspec 错误:

[PhpSpec\Exception\Locator\ResourceCreationException] 找不到适合 Bar 类的套件范围。

作为这样的可选类来测试返回值的最佳实践方法是什么?

【问题讨论】:

    标签: php phpspec


    【解决方案1】:

    将选择$source 类型的逻辑移到外部工厂函数中。

    class Foo {
    
      protected $source;
    
      public function __construct($source = []) {
        $this->source = $source;
      }
    
    }
    
    class FooFactory {
    
      public get() {
        $source = [];
        if (class_exists(Bar::class)) {
          $source = new Bar($source);
        }
    
        return new Foo($source);
      }
    
    }
    

    这允许您以两种方式显式测试Foo,和通过将所有内容移动到依赖注入模型来解耦实现。

    【讨论】:

    • 谢谢。对于我的具体实施,我宁愿避免使用工厂。我想我可以有一些AbstractFoo,因为你的答案中有Foo(直接使用数组源),并且有Foo extends AbstractFoo,我的实现检查Bar。我可以为数组测试存根AbstractFoo,并直接为Bar 测试使用Foo。即便如此,将类 仅 抽象用于测试感觉是错误的。
    • 一开始就在构造函数中硬编码Bar,这真的让我很不爽。仅凭这一点,您就应该将其搬出并搬入工厂。
    • 再次感谢您。虽然用 phpspec 测试工厂有其自身的困难,但我想我现在已经准备好了。
    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多