许多Test类或一个Test类有很多方法?

时间:2011-08-02 00:29:05

标签: unit-testing junit tdd

我有一个PersonDao,我正在编写单元测试。

PersonDao中约有18-20种方法 -

    getAllPersons() 
    getAllPersonsByCategory()
    getAllPersonsUnder21() etc

我测试这个的方法是创建一个PersonDaoTest,用大约18个测试方法测试PersonDao中的每个方法

然后我创建了一个PersonDaoPaginationTest,它通过应用分页参数来测试这18种方法。

这是否反对TDD最佳做法?我被告知这会产生混淆,并且违反最佳做法,因为这是非标准的。建议将两个类合并为PersonDaoTest。

据我所知,你的代码越多分为更多类,请发表评论。

5 个答案:

答案 0 :(得分:11)

您必须复制一组18个测试以测试新功能,这一事实表明您的PersonDao课程承担了多重责任。具体来说,它似乎负责查询/过滤和分页。您可能希望了解是否可以进行一些设计工作以将分页功能提取到单独的类中,然后可以单独进行测试。

但是在回答你的问题时,如果你发现你有一个你想保持复杂的类,那么使用多个测试类作为组织大量测试的方法是完全正确的。 @Gishu通过他们的设置分组测试的答案是一个很好的方法。 @ Ryan通过“方面”或特征进行分组的答案是另一种好方法。

答案 1 :(得分:8)

在不查看代码的情况下无法给出全面的答案......除非使用与您和您的团队相关的任何内容。

我发现在大多数情况下,根据设置分组测试效果很好。即如果5个测试需要相同的设置,它们通常很适合测试夹具。如果第6次测试需要不同的设置(或多或少)将其分解为单独的测试夹具。

这也导致测试夹具具有特征内聚性(即按功能分组的测试),试一试。我不知道有任何最佳实践表明你需要为每个生产类提供一个测试类...在实践中我发现每个生产类我有n个测试类,最好的做法是使用好名字并保持相关的测试关闭(在命名文件夹中)。

答案 2 :(得分:3)

我的2美分:当你有一个类似于它的大型课程时,就像分页一样,我发现它通常可以让更多可以理解的测试将它们全部打包成一节课。我不能声称自己是TDD大师,但我可以虔诚地实践测试优先发展。我不经常这样做,但是,我也不会为特定的类编写多个测试类。然而,许多人似乎忘记了在编写测试时分离关注点等良好的编码习惯。我不确定为什么。

答案 3 :(得分:1)

我认为每个类的一个测试类很好 - 如果你的实现有很多方法,那么你的测试类将有很多方法 - 大不了。

您可以考虑以下几点:

您的方法似乎有点“过于具体”,可能会使用一些抽象或泛化,例如,而不是getAllPersonsUnder21()考虑getAllPersonsUnder(int age)

如果您的课程有一些更一般的方面,请考虑使用一些常见的测试代码使用回调测试它们。对于一个简单的例子来说明getAllPersons()返回多个命中的测试,请执行以下操作:

@Test
public void testGetAllPersons() {
    assertMultipleHits(new Callable<List<?>> () {
        public List<?> call() throws Exception {
            return myClass.getAllPersons(); // Your call back is here
        }
    });    
}

public static void assertMultipleHits(Callable<List<?>> methodWrapper) throws Exception {
    assertTrue("failure to get multiple items", methodWrapper.call().size() > 0);
}

任何类都可以使用此静态方法来测试“some method”是否返回多个匹配。您可以扩展它以对同一个回调进行大量测试,例如在有和没有数据库连接的情况下运行它,测试它在每种情况下的行为都是正确的。

答案 4 :(得分:1)

我正在使用selenium进行Web应用程序的测试自动化。它不是单元测试,但您可能会发现某些原则适用。测试非常复杂,我们发现以满足我们所有要求的方式实现测试的唯一方法是每个类进行1次测试。因此,我们认为每个类都是一个单独的测试,然后,我们能够使用方法作为测试的不同步骤。例如:

public SignUpTest()
{
   public SignUpTest(Map<String,Object> data){}
   public void step_openSignUpPage(){}
   public void step_fillForm(){}
   public void step_submitForm(){}
   public void step_verifySignUpWasSuccessfull(){}
}

所有步骤都是相关的,它们遵循指定的顺序,如果有人失败,其他步骤将不会被执行。

当然,每个步骤本身都是一个测试,但它们一起形成了单挑测试。

要求类似于:

  1. 测试必须是数据驱动的,即与不同输入并行执行相同的测试。
  2. 测试也必须在不同的浏览器中并行运行。所以每一个 测试将运行&#34; input_size x browsers_count&#34;时间并行。
  3. 测试将集中在网络工作流程中,例如,&#34;使用有效数据注册&#34;并且它们将被分成较小的测试单元,用于工作流程的每个步骤。它会让事情变得更容易 维护和调试(当你失败时,它会说: SignUpTest.step_fillForm(),你马上就会知道错误了。
  4. 测试步骤共享相同的测试输入和状态(例如,创建的用户的ID)。想象一下,如果你进入同一个班级 不同测试的步骤,例如:

    public SignUpTest()
    {       
       public void signUpTest_step_openSignUpPage(){}
       public void signUpTest_step_step_fillForm(){}
       public void signUpTest_step_step_submitForm(){}
       public void signUpTest_step_verifySignUpWasSuccessfull(){}
    
       public void signUpNegativeTest_step_openSignUpPage(){}
       public void signUpNegativeTest_step_step_fillFormWithInvalidData(){}
       public void signUpNegativeTest_step_step_submitForm(){}
       public void signUpNegativeTest_step_verifySignUpWasNotSuccessfull(){}
    } 
    

    然后,处于属于2个测试的相同类状态将是 一团糟。

  5. 我希望我很清楚,你可能会觉得这很有用。最后,选择代表你的测试的内容:如果一个类或一个方法只是一个我认为将取决于它的决定:测试的目标是什么(在我的情况下,围绕一个特征的工作流程),什么&#39 ;更容易实现和维护,如果测试失败,你如何使故障更准确,如何使它更容易调试,什么将导致你更可读的代码等。