2010-04-24 71 views
1

我是单元测试新手,因此想做一些实践练习来熟悉jUnit框架。正确定义jUnit测试用例

我创建了一个程序,它实现一个字符串乘法器

public String multiply(String number1, String number2) 

为了测试乘法器方法,我创建了一个测试套件包含以下测试例(与所有需要的整数解析等)

public class MultiplierTest { 
    @Test 
    public void testMultiply() { 
     Multiplier multiplier = new Multiplier(); 
     // Test for 2 positive integers 
     assertEquals("Result", 5, multiplier.multiply("5", "1")); 

     // Test for 1 positive integer and 0 
     assertEquals("Result", 0, multiplier.multiply("5", "0")); 

     // Test for 1 positive and 1 negative integer 
     assertEquals("Result", -1, multiplier.multiply("-1", "1")); 

     // Test for 2 negative integers 
     assertEquals("Result", 10, multiplier.multiply("-5", "-2")); 

     // Test for 1 positive integer and 1 non number 
     assertEquals("Result", , multiplier.multiply("x", "1")); 

     // Test for 1 positive integer and 1 empty field 
     assertEquals("Result", , multiplier.multiply("5", "")); 

     // Test for 2 empty fields 
     assertEquals("Result", , multiplier.multiply("", "")); 
    } 
} 

以类似的方式,我可以创建涉及边界情况(考虑数字是int值)或甚至虚数值的测试用例。

1)但是,以上最后3个测试用例的期望值应该是多少? (一个特殊的数字表示错误?)

2)我错过了哪些额外的测试案例?

3)是测试乘数法的assertEquals()方法不够还是需要其他的方法,如assertTrue(),assertFalse(),assertSame()等

4)这是正确的方式去开发测试用例?我如何“完全”从这个练习中受益?

5)什么应该是测试乘法器方法的理想方法?

我在这里很无能。如果任何人都可以帮助回答这些问题,我将不胜感激。谢谢。

+0

只是一件小事 - 所有的测试都有“结果”作为字符串。该字符串应该是信息性的 - 例如,在第一个字符串中,您可能会说“5 * 1!= 5”。 – 2010-04-24 02:17:50

+0

这是5个问题,而不是1个, – Raedwald 2016-08-22 07:17:47

回答

3

1)但是,上面最后3个测试用例的期望值应该是多少? (一个特殊的数字表示错误?)

正如其他答复者所解释的,它取决于乘数的接口合约。您应该考虑您(或其客户,一般情况下)应该如何使用它,在发生特定错误或极端情况时应该如何处理等。在Java中,惯例是在这种情况下抛出异常。

2)我错过了哪些额外的测试用例?

这,我想起一对夫妇的情况:

// test commutativity 
assertEquals("0", multiplier.multiply("0", "5")); 
assertEquals("-1", multiplier.multiply("1", "-1")); 
assertEquals("149645", multiplier.multiply("173", "865")); 
assertEquals("149645", multiplier.multiply("865", "173")); 

// test some more unusual cases of multiplying with 0 
assertEquals("0", multiplier.multiply("-5", "0")); 
assertEquals("0", multiplier.multiply("0", "-0")); 
// test with numbers starting with '+' 
assertEquals("368", multiplier.multiply("+23", "+16")); 
assertEquals("-368", multiplier.multiply("-23", "+16")); 

// test multiplying huge values without overflow 
assertEquals("18446744073709551616", multiplier.multiply("4294967296", "4294967296")); 
assertEquals("18446744073709551616", multiplier.multiply("-4294967296", "-4294967296")); 

3)是测试乘数法的assertEquals()方法不够还是需要其他的方法,如assertTrue(),assertFalse (),assertSame()等

在这种情况下,所有你需要的是比较两个值的相等性。在其他测试中,您可能需要不同种类的断言。

4)这是开发测试用例的正确方法吗?我如何“完全”从这个练习中受益?

单元测试没有单一的“正确”方法。最接近的可能是test driven development,如果你从头开始编写代码,这是许多人(包括我自己)推荐的。

您从这个练习中受益很可能是您熟悉JUnit并尝试了一段时间的“测试者帽子”。

5)什么应该是测试乘法器方法的理想方法?

这个问题与上一个问题有什么不同?

+0

谢谢你的指点。现在有道理。 – Epitaph 2010-04-25 02:04:42

+0

对于类似的测试用例,我可以有一个包含多个assertEquals()的方法吗?例如,对于包含字符,特殊符号,字符串,空字符串等非法输入的测试用例,有1个方法testArgumentMultiply()。因为所有这些输入都会导致相同的NumberFormatException? – Epitaph 2010-04-25 23:46:42

+0

@Epitaph,纯粹主义者坚持认为人们应该在任何测试方法中只测试一件事情。我不那么挑剔。我努力在测试方法中测试单个连贯的用例,包括可能的几个断言。但是,在您的具体情况中,请注意,当调用的方法抛出异常时,调用测试方法的执行将在此处终止,因此不会执行进一步的调用。换句话说,你必须把你的每个异常测试都放到它自己独立的测试方法中。 – 2010-04-26 07:54:26

4

首先,你的代码有错,因为你有一个类,但没有功能。我假设所有这些测试都在一个功能?如果是这样,我会建议反对它。一般来说,你想一个测试,测试一个东西,所以:

public class MultiplierTests { 
    @Test 
    public void testSimpleMultiple() { 
    assertEquals(...); 
    } 

    ... 
} 

其次,你传递一个int结果在这里:

assertEquals("Result", 5, multiplier.multiply("5", "1")); 

Multiplier.multiply()返回String

那么你如何测试这取决于结果是什么。如果传入一个空字符串,它会抛出异常吗?如果是这样,你可以定义你的@Test注释说,它预计的异常被抛出:

@Test(expected = IllegalArgumentException.class) 
public void test() { 
    multiplier.multiply("", "5"); 
} 
+0

在您的IllegalArgumentException示例中,如果我使用带3个参数的assertEquals()方法,则期望值的字段应该包含如下内容 @Test(expected = NumberFormatException.class) public void testMultiply()assertEquals(“4 * a”,?,tester.multiply(“3”,“a”); } – Epitaph 2010-04-25 22:45:20

+0

@Epitaph在'IllegalArgumentException'示例中,不要使用'assertEquals()调用方法,如果没有异常,测试将失败。如果抛出了除IllegalArgumentException之外的异常,则测试将失败。只有在引发'IllegalArgumentException'时才会通过。 – cletus 2010-04-25 23:05:48

+0

谢谢。我试着为期望的值放入“新的NumberFormatException()”,它工作。那也好吗? – Epitaph 2010-04-25 23:29:14

2

你应该考虑增加测试用例来验证你的异常工作正常使用@Expected注解。基本上,写一个你知道应该产生一个异常,然后看到测试通过的情况。

确定您是否错过复杂方法中的任何情况的好方法是通过代码覆盖工具来运行它们。运行所有测试,然后查看代码覆盖率结果。如果您的代码中有部分代码未被您的测试用例访问,您可能会错过一些代码。

你可以找到一个很好的指导here

+0

你能推荐一些代码覆盖工具吗? – Carl 2010-04-24 04:21:46

+0

这里有一个很好的列表:http://java-source.net/open-source/code-coverage。 我建议你尝试http://codecover.org/ 我个人使用Atlassian的Clover,但这不是免费的工具。 – Prachi 2010-04-24 17:32:25

1

如果你真的测试的边界条件,以及你期待的数字字符串表示,或许你可以测试字符串传递给函数方法测试

@Test(expected= NumberFormatException.class) 
public void test() { 
    multiplier.multiply("a", "b"); 
} 

我克莱图斯不同意他的执行,因为他测试用例需要包含所有IllegalArgumentException,我认为测试特定的子类比使用父例外更好。

+0

我相信'IllegalArgumentException'应该只是一个例子。 – 2010-04-24 22:36:15

+0

我承认这一点,但事实是,期望一个家长的异常可以让你赶上很多其他意想不到的例外。 – Kartik 2010-04-26 18:02:01