如何使用PHPUnit测试集合类

时间:2013-07-09 17:14:12

标签: 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);
    }
}

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

  1. 添加方法hasFoo(FooInterface $foo)并在添加后检查此内容。
  2. 添加直接返回getFoos()实例的方法SplObjectStorage,并在添加后检查$foo是否在其中。
  3. removeFoo($foo)之后尝试addFoo($foo)并检查例外情况。
  4. $_foos设为公共财产,并在添加后直接检查(坏,坏,坏......)。
  5. 选项#1和#2正在更改公共接口仅用于测试目的,我不确定我的感受。它们似乎是非常通用的,有用的方法,但在我的特定情况下,我从来不需要检查集合中特定Foo实例的存在,也不需要检索所有实例,所以它真的会膨胀。此外,似乎如果我在一次测试中测试界面的多个部分,我不是真的在测试“单位”,但这或多或少只是一个哲学上的挂断。

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

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

2 个答案:

答案 0 :(得分:5)

为什么不创建一个传递给构造函数的模拟SplObjectStorage对象?然后,您可以声明在模拟上调用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);
}

removeFoo的类似内容。

执行此操作需要您更改构造函数,以便可以注入依赖项。但IMO使得代码更加清晰。也使测试更容易。

所以构造函数变为:

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

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

答案 1 :(得分: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());
}