2013-03-01 35 views
9

我有一个参数化测试类,其中有大量的单元测试,通常控制着自定义电子邮件的创建。现在类有很多测试依赖于参数化类中使用的因素,测试的流程对于每个测试都是一样的。测试的例子:如果测试中的语句

@Test 
public void testRecipientsCount() { 
    assertEquals(3, recipientsCount); 
} 

我不得不额外的funcionality增加,增加了一些额外的内部电子邮件收件人列表我的电子邮件类,这仅发生于某些案件,导致了我的问题。

可以说我想断言创建的消息数量。对于旧的测试,每种情况都是一样的,但现在它的不同取决于具体情况。对我来说,最直观的方法就是if语句添加:

@Test 
public void testRecipientsCount(){ 
    if(something) { 
     assertEquals(3, recipientsCount); 
    } 
    else { 
     assertEquals(4, recipientsCount); 
    } 
} 
... 

,但我更有经验的同事说,我们应该避免在测试类IFS(我在这有点儿同意)。

我认为在两个测试分类上进行分割测试可能会有效,但这会导致两个分类中的冗余代码(我仍然需要检查是否创建了非本地消息,它们的大小,内容等)以及其中一个添加了几行。

我的问题是:如何做到这一点,所以我不使用if或冗余代码(不使用参数化类会产生更多冗余代码)?

+0

'增加了一些额外的内部电子邮件到收件人名单“。这个内部地址列表是否被注入到类中?如果是这样,你只需擦除大部分测试的列表,并且有一个或两个'testInternalMail'测试来填充这个列表 – 2013-03-01 09:17:36

+0

我认为这对于参数化测试类来说是不可能的。添加的测试用例可能会针对每组参数运行,并且对于某些参数的断言也会有所不同。你的解决方案可以在没有参数化类的情况下工作,但我有点想避免这种情况。 – Raidmaster 2013-03-01 09:42:14

+0

您可以将您的发布代码更改为更完整(但仍然很小且假)的测试课程,以便我们了解如何设置您的参数? – 2013-03-02 00:39:03

回答

3

在我看来,Junit应该像协议一样阅读。 这意味着您可以编写冗余代码以使测试案例更易读。 为业务逻辑中的每个可能的if语句以及负面情况编写一个测试用例。这是获得100%测试覆盖率的唯一方法。 我用的结构:

- testdata preparation 
- executing logic 
- check results 
- clear data 

而且你应该写在自己的抽象类的大物体的复杂断言:

abstract class YourBusinessObjectAssert{ 
    public static void assertYourBussinessObjectIsValid(YourBusinessObject pYourBusinessObject,  Collection<YourBusinessObject> pAllYourBusinessObject) { 
for (YourBusinessObject lYourBusinessObject : pAllYourBusinessObject) { 
    if (lYourBusinessObject.isTechnicalEqual(pYourBusinessObject)) { 
    return; 
    } 
} 
assertFalse("Could not find requested YourBusinessObject in List<YourBusinessObject>!", true); 
} 
} 

它会降低你的代码的复杂性和你正在做其提供给其他开发者。

0

在我看来,单元测试应该只在可能的情况下测试一件事情。因此,我会说,如果你需要一个if语句,那么你可能需要多个单元测试 - if/else代码中的每个块都需要一个测试。

如果可能的话我会说一个测试应该读起来像一个故事 - 我的首选布局(和它不是我的主意:-) - 其相当广泛使用)是:

- given: do setup etc 
- when: the place you actually execute/call the thing under test 
- expect: verify the result 

一个单元的另一个优点测试测试只有一件事是,当发生故障时,其明确的原因是什么 - 如果您有很多可能的结果进行长时间测试,那么测试失败的原因将变得更加困难。

0

为什么不能有一个私有方法来测试每种方法常见的事情?喜欢的东西(但可能与为testCommonStuff()方法的一些输入参数):

@Test 
public void testRecipientsCountA(){ 
    testCommonStuff(); 
    // Assert stuff for test A 
} 

@Test 
public void testRecipientsCountB(){ 
    testCommonStuff(); 
    // Assert stuff for test B 
} 

private void testCommonStuff() { 
    // Assert common stuff 
} 

这样,你没有得到冗余的代码,你可以测试分割成更小的测试。如果你的测试应该测试相同的东西,那么你也可以减少测试的错误。您仍然会知道哪个测试失败,因此可追溯性应该不成问题。

+0

我使用Parametrized类,它将为每组参数运行两个测试用例。正确的方法是只运行一个,具体取决于实际参数。 – Raidmaster 2013-03-01 10:02:12

+0

@ Badman6我不完全明白。你说“但这会导致两个类中的冗余代码(我仍然需要检查是否创建非外部消息,它们的大小,内容等)”。这是否意味着你在一个或多个测试方法中使用了缩减代码?如果是这样,你可以在上面的私有方法中使用它,并从每个应该运行它的方法中调用它。 – Magnilex 2013-03-01 10:09:12

+0

它不是。收件人数量取决于参数类的参数提供程序中指定的参数。如果我想保留Parametrized类冗余代码,将会将我的测试分为两类(一类用于没有内部收件人的情况)。对于测试类来说,共享代码并不是真正的选择。你的解决方案是好的,只是不适用于参数化类 – Raidmaster 2013-03-01 10:12:52

0

我不确定在参数化测试中是否可以干净地做你的事情。如果您需要根据某些功能的哪个参数来使用不同的测试用例行为,那么最好单独测试这些功能 - 在不参数化的不同测试类中。

如果你确实想要把一切都在参数化的测试类,我会倾向于做一个辅助功能,使您的示例测试至少作为一个简单的声明内容如下:

@Test 
public void testRecipientsCount(){ 
    assertEquals(expectedCount(something), recipientsCount) 
} 

private int expectedCount(boolean which) { 
    if (something){ 
     return 3; 
    } 
    else { 
     return 4; 
    } 
}