31

方法setUp()tearDown()在每次测试之前和之后调用。但实际上,有没有关于我为什么需要这个的真实文字示例?

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

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

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

public function testSomething()
{
    $this->assertSame('foo', $this->testsub->getFoo());
}

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

4

4 回答 4

34

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

创建要测试的对象所需执行的任何操作也会进入 setup 方法,例如创建注入到测试对象的构造函数中的模拟对象。

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

唯一需要拆卸的是您的测试是否会永久留下某些内容,例如创建的文件或数据库条目。编写执行此类操作的测试确实不是一个好主意,但在某些时候,您无法再抽象,不得不接触硬盘驱动器、数据库或真实网络之类的东西。

因此,除了需要拆卸之外,还有很多设置,如果没有为此测试做任何工作,我总是删除拆卸方法。

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

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());
}
于 2012-12-18T23:10:14.107 回答
4

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

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

这只是一个之前/之后的钩子,一般来说这是一件很时髦的事情。使用它来让您的生活更轻松,或者不要使用它。

于 2012-12-18T22:57:45.547 回答
2

在接受的答案中提供的示例中存在内存泄漏。您应该添加拆解:

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

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

于 2018-10-12T16:09:59.963 回答
1

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

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

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

我们还假设您的测试方法实际上可能会修改购物车的商品,并用运费信息装饰它们。您不希望一次测试中的信息渗入下一次测试,因此您只需在最后取消设置购物车。

public function tearDown()
    unset($this->cart);
}
于 2012-12-18T23:03:30.457 回答