关于单元测试结构的思考

时间:2013-01-23 17:15:04

标签: java unit-testing junit

我正在考虑如何为我的项目编写测试。目前,测试结构如下:

RealClass 
{ 
      method1; 
      method2; 
      ...
}

和完全相同的测试类结构:

TestClass {
   testMethod1; 
   testMethod2; 
   ...
 }

但是,我不喜欢它,因为我在一种测试方法中放了太多的测试用例......

可能我应该使用这样的结构:

TestClass {
   testMethod1Opt1; 
   testMethod1Opt2; 
   ... 
   testMethod2Opt1; 
   ...}

你是如何编写单元测试的?

我的测试代码示例:(非常简单的测试)

public void testIsAppUser() {
    // My (Artem`s Zinnatullin) uId
    final long artemZinnatullinUId = 172672179;

    try {
        assertTrue(usersApi.isAppUser(artemZinnatullinUId));
    } catch (Exception e) {
        fail(e.getMessage());
    }

    // Pavel`s Durov uId
    final long durovUId = 1;

    try {
        assertFalse(usersApi.isAppUser(durovUId));
    } catch (Exception e) {
        fail(e.getMessage());
    }

    // By default uId == current user`s (who has authorized) uId 
    try {
        assertTrue(usersApi.isAppUser(null));
    } catch (Exception e) {
        fail(e.getMessage());
    }
}

我在想什么:

public void testIsAppUser1() {
    // My (Artem`s Zinnatullin) uId
    final long artemZinnatullinUId = 172672179;

    try {
        assertTrue(usersApi.isAppUser(artemZinnatullinUId));
    } catch (Exception e) {
        fail(e.getMessage());
    }
}

public void testIsAppUser2() {
    // Pavel`s Durov uId
    final long durovUId = 1;

    try {
        assertFalse(usersApi.isAppUser(durovUId));
    } catch (Exception e) {
        fail(e.getMessage());
    }
}

public void testIsAppUser3() {
    // By default uId == current user`s (who has authorized) uId
    try {
        assertTrue(usersApi.isAppUser(null));
    } catch (Exception e) {
        fail(e.getMessage());
    }
}

请给我建议。

2 个答案:

答案 0 :(得分:2)

评论:

  1. 而不是try{} catch(){ fail() }只需将throws Exception添加到测试方法中。 JUnit会自动使测试失败保留堆栈跟踪。这将使错误修复变得更加容易。

  2. 创建小型测试方法。这造成了名称问题:如何提出许多好名字?这里的解决方案是在逻辑测试之后命名测试,而不是它调用的方法。

    如果要查看调用的方法,请使用代码覆盖率工具,如JaCoCo

    所以第一次测试应该被称为testIsArtemsZinnatullinAppUser()。作为指导:每当您觉得需要评论来解释测试的内容时,测试名称是错误的。使用您在评论中写的任何内容来创建测试名称。

  3. 你应该进行较小测试的原因是JUnit会因第一个问题而停止。因此,如果您在一个测试用例中有20个测试而第3个测试失败,那么将无法运行17个测试。但这17项测试可能包含有价值的信息,有助于找出问题所在。

    如果它们都成功了,那么这可能是一个特定的问题。如果许多测试失败,则问题必须出在共享代码中。

答案 1 :(得分:1)

构建测试的第二种方法要好得多。这样每种测试方法都会以不同的方式来破解方法,所以你不会遇到修复方法中的一个bug的情况,然后让测试失败一点(这样一个错误就会阻止你看到其他)。更重要的是,测试方法比测试方法映射到被测对象的方法要小且注意力集中。

另外,不要捕获异常,JUnit会为你做到这一点。将throws Exception添加到每个测试方法的签名中。如果你想检查是否真的抛出异常,那么你可以在测试中捕获它,例如:

try {
    objectUnderTest.doSomethingThatShouldThrowFooException();
    fail("should've thrown an exception before getting here");
}
catch (FooException fooEx) {
    // yay. my test passed
}

,但是:

的样板
} catch (Exception e) {
    fail(e.getMessage());
}

是不必要的。