测试项目中选择性包含的 Class 的使用

Testing Use of Class Optionally Included in Project

我有一个 class 如下所示:

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] Can not find appropriate suite scope for class Bar.

像这样测试 return 值是可选 class 的最佳实践方法是什么?

将选择 $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两种方式通过将所有内容移动到依赖注入模型来解耦实现。