JUNIT测试void方法

met*_*aon 58 java junit

我有一个充满void方法的java类,我想进行一些单元测试以获得最大的代码覆盖率.

例如,我有这个方法:

protected static void checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
}
Run Code Online (Sandbox Code Playgroud)

由于我翻译代码以便更好地理解,因此它的名字很差.每个方法都以某种方式验证参数是否有效并且写得很好.

示例:

private static void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        ErrorFile.errorMessages.add("There is a dollar sign in the specified parameter");
    }
}
Run Code Online (Sandbox Code Playgroud)

我的单元测试正在覆盖小方法,因为我要求他们检查ErrorFile是否包含错误消息,但我不知道如何测试我的方法checkIfValidElements,它什么都不返回或什么都不改变.当我使用Maven运行代码覆盖时,它告诉我单元测试会覆盖我课程的这一部分.

我看到的唯一方法是更改​​此方法以返回int或bollean值,如下所示:

protected static int checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用这种方法,我能够做一个断言等于,但在我看来这样做是徒劳的.问题是我有几个类似这样的类,它降低了我的单元测试覆盖率%.

Jon*_*eet 64

我想进行一些单元测试以获得最大的代码覆盖率

代码覆盖率永远不应该是编写单元测试的目标.您应该编写单元测试来证明您的代码是正确的,或者帮助您更好地设计它,或者帮助其他人理解代码的意图.

但是我没看到我如何测试我的方法checkIfValidElements,它什么都不返回或什么都没改变.

那么你应该给出一些测试,它们之间检查所有7个方法都被正确调用 - 无论是参数无效还是有效参数,都要检查ErrorFile每次的结果.

例如,假设某人删除了以下呼叫:

method4(arg1, arg2);
Run Code Online (Sandbox Code Playgroud)

...或意外更改了参数顺序:

method4(arg2, arg1);
Run Code Online (Sandbox Code Playgroud)

你会怎么注意到这些问题?从那里开始,设计测试来证明它.

  • @Gobliins:代码覆盖率是一个数字.如果数字上升而你实际上对代码的可靠性没有任何信心,那有什么意义呢?目标应该是提高代码的质量(设计和实现).覆盖率是这方面的一个*可能*指标,但完全有可能对代码的关键和复杂方面进行良好测试,并且仍然具有相对较低的覆盖率 - 或者覆盖率高但测试不佳. (12认同)
  • @Gobliins:我手边没有任何链接.但仅仅因为一条线被覆盖并不意味着你实际上已经覆盖了所有角落的情况.考虑一个简单的比较反向器,它只返回`-original.compare(x,y)`.您可以通过单个测试完全覆盖 - 但这并不意味着代码是正确的,事实上,如果原始比较返回"Integer.MIN_VALUE"则不行. (3认同)
  • @Alon“现在,最好在实现该方法之前创建单元测试”。您所说的是测试驱动开发(TTD)。这是多种可能的编码方法之一。你还有很多其他人。这不是“现在”:)。问题在于哪种方法更适合您的软件。 (2认同)

Gra*_*ham 23

如果你的方法没有副作用,并且没有返回任何东西,那么它没有做任何事情.

如果您的方法进行了一些计算并返回该计算的结果,那么显然可以断言返回的结果是正确的.

如果您的代码没有返回任何但有副作用,您可以调用代码然后断言正确的副作用已经发生.副作用将决定您如何进行检查.

在您的示例中,您从非返回函数调用静态方法,这使得它很棘手,除非您可以检查所有这些静态方法的结果是否正确.从测试的角度来看,更好的方法是在调用方法时注入实际对象.然后,您可以使用EasyMock或Mockito之类的东西在单元测试中创建Mock对象,并将模拟对象注入到类中.然后,Mock对象允许您断言正确的函数被调用,具有正确的值并且顺序正确.

例如:

private ErrorFile errorFile;

public void setErrorFile(ErrorFile errorFile) {
    this.errorFile = errorFile;
}

private void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的测试中你可以写:

public void testMethod1() {
    ErrorFile errorFile = EasyMock.createMock(ErrorFile.class);
    errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    EasyMock.expectLastCall(errorFile);
    EasyMock.replay(errorFile);

    ClassToTest classToTest = new ClassToTest();
    classToTest.setErrorFile(errorFile);
    classToTest.method1("a$b");

    EasyMock.verify(errorFile); // This will fail the test if the required addErrorMessage call didn't happen
}
Run Code Online (Sandbox Code Playgroud)

  • 这是副作用,它正在修改某些东西 (10认同)
  • 通常,这些天没有人会实现发送电子邮件的所有逻辑.它只是对具有发送电子邮件逻辑的组件的调用.因此,单元测试应该测试使用正确的参数调用该方法.实际发送电子邮件的组件应该具有自己的单元测试. (4认同)
  • <<如果你的方法没有副作用,并且没有返回任何东西,那么它没有做任何事情.>>那不是真的,如果你的方法只是修改了对象的状态怎么办? (2认同)
  • 如何发送电子邮件?您可能需要为它提供一个模拟类来进行电子邮件发送,或者为它提供一个伪造的邮件服务器来处理电子邮件连接,然后检查它们在这些方面是否正常工作。再次发送电子邮件是一种副作用,可以监视这种副作用。 (2认同)

Ser*_*scu 6

你可以学习一些叫做“mocking”的东西。例如,您可以使用它来检查是否: - 调用了函数 - 调用了函数 x 次 - 函数至少调用了 x 次 - 使用一组特定参数调用了函数。例如,在您的情况下,您可以使用模拟来检查 method3 是否被调用一次,无论您作为 arg1 和 arg2 传递什么。

看看这些: https://code.google.com/p/mockito/ https://code.google.com/p/powermock/


Jef*_*rey 5

您仍然可以通过断言它具有适当的副作用来对 void 方法进行单元测试。在您的method1示例中,您的单元测试可能类似于:

public void checkIfValidElementsWithDollarSign() {
    checkIfValidElement("$",19);
    assert ErrorFile.errorMessages.contains("There is a dollar sign in the specified parameter");
}
Run Code Online (Sandbox Code Playgroud)