2

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

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);
    }
}

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

  1. 添加一个方法hasFoo(FooInterface $foo)并在添加后检查它。
  2. 添加一个getFoos()直接返回SplObjectStorage实例的方法,并$foo在添加后检查是否在其中。
  3. 尝试在removeFoo($foo)之后addFoo($foo)检查是否有异常。
  4. 创建一个公共属性并在添加后直接检查$_foos它(坏,坏,坏......)。

选项 #1 和 #2 只是为了测试目的而更改公共接口,我不确定我对此有何感受。从表面上看,它们似乎是非常通用、有用的方法,但在我的特殊情况下,我不需要检查Foo集合中特定实例的存在,也不需要检索所有实例,所以它真的会只是臃肿。此外,似乎如果我在一次测试中测试界面的多个部分,我并不是真的在测试一个“单元”,但这或多或少只是一种哲学上的挂断。

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

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

4

2 回答 2

5

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

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);
}

和类似的东西removeFoo

这样做确实需要您更改构造函数以便注入依赖项。但是 IMO 这使代码更清楚地了解正在发生的事情。也使测试变得更容易。

所以构造函数变成:

public function __construct(SPLObjectStorage $storage) {
    $this->_foos = $storage;
}

如果这样做变得难以构建类,则表明该类做得太多,应该将其重构为更多、更小的类。

于 2013-07-09T21:51:05.090 回答
0

您没有发布用于获取集合的公共访问器,但我相信您有一个,否则将 foos 添加/删除到公共无法访问的数组是没有意义的。所以你可以尝试类似(phpunit 3.6,php 5.4):

public function setUp()
{
    $this->NumbersCollection = new NumbersCollection;
}

public function tearDown()
{
    unset($this->NumbersCollection);
}

public function testNumbersCollection()
{
    $this->NumbersCollection->addNumber(1);
    $this->NumbersCollection->addNumber(2);

    $this->assertSame(3, $this->NumbersCollection->sum());
    $this->assertSame(2, $this->NumbersCollection->product());

    $this->NumbersCollection->removeNumber(1);

    $this->NumbersCollection->addNumber(7);

    $this->assertSame(9, $this->NumbersCollection->sum());
    $this->assertSame(14, $this->NumbersCollection->product());
}
于 2013-07-09T17:29:58.943 回答