我已经对课程进行了单元测试,现在如何开始集成测试?


19

我编写了一个类,用于管理MailChimp列表上的收件人,称为MailChimpRecipient。它使用MCAPI类,它是第三方API包装器。

http://apidocs.mailchimp.com/api/1.3/ http://apidocs.mailchimp.com/api/downloads/

我将MCAPI对象传递给MailChimpRecipient对象的构造函数,因此我已经使用PHPUnit编写了单元测试,该单元测试可以测试我自己的类中的所有逻辑(我不测试MCAPI类)。我有100%的代码覆盖率,所有测试均通过。这是通过模拟和存根MCAPI对象来完成的。

我的下一步是使用PHPUnit编写集成测试,在该测试中,我将使用真实的MCAPI对象构造MailChimpRecipient固定装置,并设置为使用真实的MailChimp列表。

我写了我认为是集成测试的内容,它基本上是在对象的公共接口上再次运行测试,例如:

public function testAddedRecipientCanBeFound()
{
    $emailAddress = 'fred@fredsdomain.com';
    $forename = 'Fred';
    $surname = 'Smith';

    // First, delete the email address if it is already on the list
    $oldRecipient = $this->createRecipient();
    if($oldRecipient->find($emailAddress))
    {
        $oldRecipient->delete();
    }
    unset($oldRecipient);

    // Add the recipient using the test data
    $newRecipient = $this->createRecipient();
    $newRecipient->setForename($forename);
    $newRecipient->setSurname($surname);
    $newRecipient->setEmailAddress($emailAddress);
    $newRecipient->add();
    unset($newRecipient);

    // Assert that the recipient can be found using the same email address
    $this->assertTrue($this->_recipient->find($emailAddress));
}

“集成”测试不会测试该类的任何内部结构-它只是确保在给定真实的MCAPI对象的情况下,它的行为与所宣传的一样。

它是否正确?这是进行整合测试的最佳方法吗?毕竟,内部组件已经通过单元测试进行了测试。我是否认为集成测试可以根据其行为的宣传方式来测试其是否真正起作用?

为了更进一步,MailChimpRecipient类实现了一个接口,该接口也将由其他类实现。想法是使用工厂将不同类型的邮件列表收件人对象传递给我的代码,尽管使用不同的邮件列表提供程序,但它们都执行相同的操作。由于我的集成测试测试了该接口,因此如何将该接口用于实现该接口的所有类?然后,将来,如果我设计一个可互换使用的新类,则可以在将其插入项目之前运行相同的集成测试。

听起来合理吗?单元测试可以测试对象的内部,集成测试可以确保其行为与广告一样?


4
我认为您的测试逻辑太多。在执行断言之前,您需要运行大量代码。您可能首先要测试删除收件人。但这不是在回答您的问题,而只是在评论。
hakre 2012年

1
好吧,您应该利用该setUp功能来建立运行测试的基础。如果输入未定义,那么您就无法真正测试。输入内容必须准确,严格且始终相同。如果不满足测试的前提条件,请跳过测试。然后分析为什么跳过,以及是否需要添加其他测试和/或未setUp正确完成。
hakre 2012年

1
另外,不要在自己的测试中对测试值进行硬编码,而要使这些类成为成员,以便它们可以在测试之间共享(并在中心位置更改)或使用DataProvider(该功能将输入作为测试的参数提供)。
hakre 2012年

1
输入测试功能所运行的所有内容的含义。在测试添加收件人时,您要确保它不存在,因此至少应断言删除,以防其被删除。否则,不能确保测试的前提条件是可测试的。
hakre 2012年

1
+1表示很好的问题,但也投票赞成迁移给程序员。似乎正是有关测试策略的问题所在
GordonM 2012年

Answers:


17

测试代码时,应注意三个方面:

  • 场景测试
  • 功能测试
  • 单元测试

通常,每个类别中的测试数量将具有金字塔的形状,这意味着在底部的很多单元测试,在中间的一些功能测试以及仅是一些场景测试。

使用单元测试,您可以模拟出被测试类使用的所有内容,然后以纯隔离的方式对其进行测试(这就是为什么确保在类内部检索通过注入的所有依赖项以便可以在测试下将其替换的原因很重要)。

通过单元测试,您可以测试所有可能性,因此不仅可以测试“快乐之路”,还可以测试所有错误情况。

如果完全确定所有单元都是独立工作的,则可以编写一些测试(功能测试)以确保单元组合后也能正常工作。然后编写脚本测试,测试所有功能模块之间的接线。

例如,假设您要测试一辆汽车。

您可以组装整辆汽车,并作为驾驶员检查所有可能的状况,但这确实很难做到。

取而代之的是,您将尝试所有可能的引擎的一小部分(单元测试)

然后,您将测试整个发动机(与汽车分开),这将是一项功能测试。

作为最后的测试,您将钥匙插入,启动汽车,然后将其开到停车场。如果这样可以正常工作,那么您就知道所有零件(电池,燃油,发动机,..)都已连接,并且由于对它们进行了隔离测试,因此可以确定整个汽车是否正常运行。

因此,在您的情况下,您在单元测试中测试了所有错误条件和满意的路径,并且知道仅需使用“实际组件”进行端到端测试,以检查接线是否正确。

其他几点

  • 在单元测试中避免条件逻辑。如果必须清理,则使用某种全局状态,测试可能会突然相互影响。
  • 不要指定与测试无关的任何数据。如果我要更改姓氏或姓氏,测试会失败吗?可能不是因为重要的电子邮件地址,而是因为您在测试中明确提到了该地址,所以我不确定。尝试查看构建器模式以构建测试数据,并使其明确真正重要的内容。

谢谢,这证实了我的想法。只是要澄清-这不是单元测试。我已经编写了一个单元测试,该测试可以完全隔离地测试对象,并具有100%的对象代码覆盖率。这本来是一个集成测试,以确保在我将真实的MCAPI对象注入其中时可以正常运行。我只需要删除添加到列表中的所有收件人-就是全部清除工作,并且已实施该过程以确保所有测试都不会相互影响。您会建议什么呢?

1
是的 我了解您已经进行了单元测试。MCAPI对象是否跟踪收件人,是否需要清理?如果是第三方的“问题”,那么在集成测试中您无能为力。如果您跟踪列表,则应确保避免使用全局数据(和单例),以确保测试不会相互影响。在理想环境中,在测试开始/结束时清理工作会指出设计缺陷,但在现实世界中,您无法总是避免这种情况。
Wouter de Kort 2012年

1
我要补充一点,场景测试可能并不是PHPUnit真正适合的。Yu可能希望查看一些可以在浏览器中运行的工具,例如Selenium,或可以模拟浏览器的工具,例如jMeter。
GordonM 2012年

谢谢你们!在编写良好的可测试代码方面,确实有很多东西要学习,但是还没有。我已为自己订购了这本书的副本:amazon.co.uk/…。希望大家在我读完这些内容后,会说得更有意义。@Wouter,我只是删除一个收件人,因为该测试会导致将电子邮件地址添加到列表中。我正在删除它,以便该列表不受该测试的影响。

1
@LewisBassett我不是Php开发人员,但是xUnit测试模式(amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054)绝对是一本好书。而且misko.hevery.com/code-reviewers-guide上的文章也很有趣。
Wouter de Kort 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.