如何使用PHPUnit测试集合类

FtD*_*Xw6 2 php phpunit

我有一个类似于此的类(为简洁起见,删除了一些逻辑):

class FooCollection {
    protected $_foos;

    public function __construct() {
        $this->_foos = new SplObjectStorage();
    }

    public function addFoo(FooInterface $foo) {
        $this->_foos->attach($foo);
    }

    public function removeFoo(FooInterface $foo) {
        $this->_foos->detach($foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

我想用PHPUnit 来测试addFoo()removeFoo()方法,我想知道最好的策略是什么呢?据我所知,我只有几个选择:

  1. 添加方法hasFoo(FooInterface $foo)并在添加后检查此方法.
  2. 添加一个getFoos()直接返回SplObjectStorage实例的方法,并$foo在添加后检查是否在其中.
  3. 尝试removeFoo($foo)之后addFoo($foo)并检查异常.
  4. 制作$_foos公共财产并在添加后直接检查(坏,坏,坏......).

选项#1和#2正在改变公共接口仅用于测试目的,我不确定我对此的看法.它们似乎是非常通用的,有用的方法,但在我的特定情况下,我从来不需要检查Foo集合中特定实例的存在,也不需要检索所有实例,所以它真的会只是臃肿.此外,似乎如果我在一次测试中测试界面的多个部分,我不是真的在测试一个"单位",但这或多或少只是一个哲学挂断.

选项#3对我来说似乎很尴尬.

选项#4是一个非常糟糕的主意,我甚至不应该列出它,因为即使在这里建议,我也不会这样做.

Sch*_*eis 5

为什么不创建一个SplObjectStorage传递给构造函数的模拟对象?然后你可以断言在mock上调用attachdetach方法.

function testAttachFOO() {
    $mockStorage = $this->getMockBuilder('SplObjectStorage')
                    ->setMethods(array('attach'))
                    ->getMock();

    $mockFoo = $this->getMock('FooInterface');

    $mockStorage->expects($this->once())
        ->method('attach')
        ->with($mockFoo);

    $collection = new FooCollection($mockStorage);

    $collection->addFoo($mockFoo);
}
Run Code Online (Sandbox Code Playgroud)

和类似的东西removeFoo.

这样做需要您更改构造函数,以便您可以注入依赖项.但IMO使得代码更加清晰.也使测试更容易.

所以构造函数变成:

public function __construct(SPLObjectStorage $storage) {
    $this->_foos = $storage;
}
Run Code Online (Sandbox Code Playgroud)

如果这个类变得难以构建,那就表明该类做得太多,应该重构为更多更小的类.