71

我有一个充满 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();
}

它的名字不好是有原因的,因为我翻译了代码以便更好地理解。每种方法都验证参数是否以某种方式有效并且编写得很好。

例子 :

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");
    }
}

我的单元测试很好地涵盖了小方法,因为我要求他们检查 ErrorFile 是否包含错误消息,但是我看不到如何测试我的方法 checkIfValidElements,它什么也不返回或什么也不改变。当我使用 Maven 运行代码覆盖率时,它告诉我单元测试并没有涵盖我课程的这一部分。

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

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;
}

使用这种方法,我可以进行断言等于,但在我看来,这样做是徒劳的。问题是我有几个这样设计的类,它降低了我的单元测试覆盖率。

4

7 回答 7

86

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

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

但我看不到如何测试我的方法 checkIfValidElements,它什么也不返回或什么也不改变。

好吧,您可能应该进行一些测试,在它们之间检查是否正确调用了所有 7 个方法 - 使用无效参数和有效参数,检查ErrorFile每次的结果。

例如,假设有人删除了对以下内容的调用:

method4(arg1, arg2);

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

method4(arg2, arg1);

你会如何注意到这些问题?从那开始,设计测试来证明它。

于 2013-04-16T18:00:06.757 回答
30

如果您的方法没有副作用,并且没有返回任何内容,那么它什么也没有做。

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

如果您的代码没有返回任何内容但确实有副作用,您可以调用该代码,然后断言发生了正确的副作用。副作用是什么将决定您如何进行检查。

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

例如:

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");
    }
}

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

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
}
于 2013-04-16T19:22:16.753 回答
5

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

public void checkIfValidElementsWithDollarSign() {
    checkIfValidElement("$",19);
    assert ErrorFile.errorMessages.contains("There is a dollar sign in the specified parameter");
}
于 2013-04-16T18:00:12.360 回答
4

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

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

于 2014-11-05T15:30:37.097 回答
1

我认为你应该避免写副作用的方法。从您的方法返回 true 或 false,您可以在单元测试中检查这些方法。

于 2013-04-16T18:06:02.547 回答
0

如果您的方法无效并且您想检查异常,您可以使用expectedhttps ://weblogs.java.net/blog/johnsmart/archive/2009/09/27/testing-exceptions-junit-47

于 2014-04-17T11:56:18.393 回答
0

如果在您的情况下可能,您可以使您的方法method1(arg1)... method7() 受保护而不是私有,这样它们就可以从同一包中的测试类中访问。然后您可以简单地分别测试所有这些方法。

于 2018-04-09T11:46:14.150 回答