关于PHPUnit中应该如何使用setUp()和tearDown(),有什么实际的例子吗



在每次测试前后调用方法setUp()tearDown()。但真的,有什么真正的例子可以说明我为什么需要这个吗?

检查其他人的测试,我总是看到这样的东西:

public function setUp()
{
$this->testsub = new TestSubject();
}
public function tearDown()
{
unset($this->testsub);
}
public function testSomething()
{
$this->assertSame('foo', $this->testsub->getFoo());
}

当然,这种方式与"旧的"局部变量方式几乎没有区别。

如果您单独执行每个测试方法,那么您的测试代码将共享许多行,这些行只是创建要测试的对象。这个共享代码可以(但不应该)进入设置方法。

创建要测试的对象所需要做的任何事情也会进入设置方法,例如创建注入到测试对象的构造函数中的mock对象。

这些都不需要拆除,因为下一次对安装程序的调用将使用一组新的对象初始化类成员变量。

唯一需要拆除的是,如果您的测试永久性地留下了一些东西,比如创建的文件或数据库条目。写这样的测试真的不是一个好主意,但在某种程度上,你不能再抽象了,必须接触硬盘、数据库或真正的网络。

因此,需要的设置比拆卸多得多,如果这个测试没有工作要做,我总是删除拆卸方法。

关于模拟,我是这样工作的:

private $_mockedService;
private $_object;
protected function setUp()
{
$this->_mockedService = $this->getMock('My_Service_Class');
$this->_object = new Tested_Class($this->_mockService);
}
public function testStuff()
{
$this->_mockedService->expects($this->any())->method('foo')->will($this->returnValue('bar'));
$this->assertEquals('barbar', $this->_object->getStuffFromServiceAndDouble());
}

您可以实例化一堆fixture对象,并在每个测试中将它们作为实例变量使用,而不是为每个测试单独构建它们。

您可以在setUp中创建类似文件句柄的资源,然后确保在tearDown中关闭它们。如果您正在编写临时文件,可以确保删除它们。如果你打开了一个数据库连接,你可以关闭它(尽管你可能想在其他地方这样做——setupBeforeClass/tearDownAfterClass,它会为每个测试文件调用,而不是为每个测试用例调用。)

这只是一个前后挂钩,这是一个很好的东西。使用它可以让你的生活更轻松,或者不要使用它。

在所提供的示例中,接受的答案中存在内存泄漏。你应该添加tearDown:

protected function tearDown()
{
$this->_mockedService = null;
}

PHPUnit为每个测试方法调用创建新的测试用例对象。因此,如果有4个测试方法,那么将有4个对象,并且将创建4个mockedService。直到脚本(整个测试套件)结束,它们才会被删除。因此,您需要在tearDown中删除所有对象并取消设置所有变量,以防止内存泄漏。

您几乎可以在测试的类中有依赖项的任何时候使用它。这方面的一个经典示例可能是某种存储应用程序状态的对象(会话对象、购物车等)

例如,我有一个类,它将计算购物车对象定义的购物车内容的运输成本。假设这个购物车是通过依赖项注入传递到运输计算类中的。要测试类的大多数方法,您可能需要实际实例化一个cart对象并在类中设置它,以便对各种方法进行单元测试。您可能还需要将项目添加到购物车中。所以你可能会有这样的设置:

public function setUp()
{
$this->cart = new cart();
$this->cart->add_item('abc');
$this->cart->add_item('xyz');
}

我们还假设您的测试方法实际上可能会修改购物车的项目,用运输成本信息装饰它们。你没有;我不想让一次测试的信息流到下一次,所以你只需要在最后取消设置购物车。

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

最新更新