2010-06-11 209 views
2

我在测试套件中运行的一些JUnit 4测试有问题。JUnit 4测试套件问题

如果我单独运行测试,它们的工作没有问题,但是当它们大部分运行在套件中时,90%的测试方法失败并出错。我注意到,总是第一次测试正常,但其余的都失败了。另一件事是一些测试方法没有以正确的顺序执行(反射不能按预期工作,或者因为方法的检索不一定在创建的顺序中)。如果有多个测试使用同名的方法,通常会发生这种情况。我试图调试一些测试,看起来从一行到下一行,某些属性的值变为null

有谁知道这是什么问题,或者如果行为是“正常的”?

在此先感谢。

P.S: OK,测试不依赖于对方,他们没有这样做,他们都有@BeforeClass@Before@After@AfterClass所以之间的测试一切都清理。测试使用数据库,但在@BeforeClass的每次测试之前数据库都会被清除,所以这不应该是问题。

Simplefied例如:

测试套件:

import org.junit.BeforeClass; 
import org.junit.runner.RunWith; 
import org.junit.runners.Suite; 
importy testclasses...; 

@RunWith(Suite.class) 
@Suite.SuiteClasses({ Test1.class, Test2.class }) 
public class TestSuiteX { 
@BeforeClass 
public static void setupSuite() { System.out.println("Tests started"); } 
@AfterClass 
public static void setupSuite() { System.out.println("Tests started"); } 
} 

测试: 测试是在Glassfish上运行的服务器应用程序测试functionalily。

现在,这些测试扩展了一个基类,该基类具有清除数据库和登录名的@BeforeClass方法以及只进行注销的@AfterClass。 这不是问题的根源,因为在介绍此课程之前发生了同样的事情。

该类有一些公共静态属性,在其他测试中未使用并实现2个controll方法。

其余的类,在这个例子中,这两个类扩展了基类,并且不支持继承的controll方法。的测试类的

实施例:

imports.... 

    public class Test1 extends AbstractTestClass { 
    protected static Log log = LogFactory.getLog(Test1.class.getName()); 

    @Test 
    public void test1_A() throws CustomException1, CustomException2 { 

     System.out.println("text"); 

     creates some entities with the server api. 
     deletes a couple of entities with the server api. 

     //tests if the extities exists in the database 
     Assert.assertNull(serverapi.isEntity(..)); 

    } 

} 

和第二:

public class Test1 extends AbstractTestClass { 

    protected static Log log = LogFactory.getLog(Test1.class.getName()); 

    private static String keyEntity; 
    private static EntityDO entity; 

    @Test 
    public void test1_B() throws CustomException1, CustomException2 { 

     System.out.println("text"); 

     creates some entities with the server api, adds one entities key to the static attribute and one entity DO to the static attribute for the use in the next method. 
     deletes a couple of entities with the server api. 

     //tests if the extities exists in the database 
     Assert.assertNull(serverapi.isEntity(..)); 

    } 

    @Test 
    public void test2_B() throws CustomException1, CustomException2 { 

     System.out.println("text"); 

     deletes the 2 entities, the one retrieved by the key and the one associated with the static DO attribute 

     //tests if the deelted entities exists in the database 
     Assert.assertNull(serverapi.isEntity(..)); 

    } 

这是一个基本的例子,实际的测试是较复杂的,但我试图与简化测试和仍然它确实不行。 谢谢。

+1

您可以发布一个测试示例并解释您如何运行测试套件。 – 2010-06-11 10:30:38

+0

该测试套件是一个JUnit 4测试套件,它具有所有测试类的设置,并且有一个@BeforeClass和一个@AfterClass,它只提供一些次要信息(基本字符串)。 – Hypnus 2010-06-11 10:55:41

+0

您发布的代码留下了最重要的细节:1)AbstractTestClass,2)@BeforeClass,@Before,@After,@AfterClass方法,3)keyEntity和实体初始化的方式和时间,4)哪个测试失败,怎么样 ? – 2010-06-11 15:39:11

回答

1

您似乎是在假定执行方法的顺序是固定的情况下构建测试套件的。这是错误的 - JUnit不保证测试方法的执行顺序,所以你不应该依赖它。

这是设计 - 单元测试应该完全独立于彼此。为了保证这一点,JUnit创建了一个独立的新测试类实例来执行每个测试方法。因此,无论您使用某种方法设定的属性,下一个属性都会丢失。

如果你有共同的测试设置/拆卸代码,你应该把它分成不同的方法,用@Before/@After注释。这些都是在每种测试方法之前和之后执行的。

更新:你写

数据库每次测试前在@BeforeClass

如果这不是一个错字被清除,这可能是你的问题的根源。 DB应该在@Before方法中清除 - @BeforeClass对于每个类只运行一次。

+0

好吧,测试不依赖于对方,但它们的方法是这样做的,因此我不能将数据库清理代码放在@Before方法中,因为这样它将在每个方法之前清理数据库,并且它不起作用。如果您认为我将数据库清理代码放在了套件的@BeforeClass中,情况并非如此。谢谢。 – Hypnus 2010-06-11 13:07:49

+0

@Hypnus,你所说的上面的“测试”是一个测试课,对吧?显然我们在这里有一个术语不匹配。测试类可能包含许多测试方法。在单元测试的说法中,每个方法代表一个单独的_test_。而这些测试 - 即**测试方法** - 不应该相互依赖。 – 2010-06-11 13:21:25

3

您描述的情况听起来像是一个副作用问题。你提到测试单独运行良好,但依赖于操作顺序:这通常是一个关键症状。

设置整套测试用例的挑战之一是确保每个测试都从干净状态开始,执行测试,然后自行清理,将所有内容都恢复为干净状态。

请记住,有些情况下标准清理例程(例如,@Before@After)是不够的。前段时间我遇到的一个问题是在一组数据库测试中:作为测试的一部分,我将记录添加到数据库中,并且需要专门删除刚刚添加的记录。

因此,有时您需要添加特定的清理代码才能恢复到原始状态。

0

要小心如何使用@BeforeClass来设置事情的一劳永逸,并且@Before要在每次单独测试之前设置事物。并且要小心实例变量。

如果您可以发布出现问题的简单示例,我们可能会提供更具体的帮助。

+0

谢谢,我会在2个小时内做一些紧急工作。 – Hypnus 2010-06-11 10:57:19

+0

我已经为我的案例添加了一个简化的示例。我试图直接使用JUnit在包上运行测试,但仍然无效(某些方法在不同位置失败)。谢谢。 – Hypnus 2010-06-11 14:13:14