我在使用测试套件运行的一些JUnit 4测试时遇到问题。
如果我单独运行测试它们没有任何问题,但是当它们在大多数套件中运行时,90%的测试方法都会失败并出现错误。我注意到的是,总是第一次测试工作正常,但其余测试都失败了。另一件事是,一些测试方法没有以正确的顺序执行(反射不能按预期工作,或者因为方法的检索不一定是在创建的顺序中)。如果存在多个具有相同名称的方法的测试,则通常会发生这种情况。我尝试调试一些测试,似乎从一行到下一行,某些属性的值变为null
。
有谁知道问题是什么,或者行为是否“正常”?
提前致谢。
P.S .:
好的,测试不依赖于彼此,它们都没有,并且它们都有@BeforeClass
,@Before
,@After
,@AfterClass
所以在测试之间一切都被清除了。测试使用数据库,但数据库在@BeforeClass
中的每个测试之前被清除,因此这不应该是问题。
简单的例子:
TEST SUITE:
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上运行的服务器应用程序上进行功能测试。
现在,测试扩展了一个具有@BeforeClass的基类 - 清除数据库和登录的方法以及仅进行注销的@AfterClass。 这不是问题的根源,因为在介绍这个类之前发生了同样的事情。
该类具有一些公共静态属性,这些属性未在其他测试中使用,并实现了2个控制方法。
其余的类,对于这个例子,这两个扩展了基类,并没有强化继承的控制方法。
测试类的示例:
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(..) );
}
这是一个基本的例子,实际测试更复杂,但我尝试使用简化测试,但仍然无法正常工作。 谢谢。
答案 0 :(得分:3)
您描述的情况听起来像副作用问题。你提到测试在隔离状态下运行良好但依赖于操作顺序:这通常是一个严重的症状。
设置一整套测试用例的部分挑战是确保每个测试从干净状态开始,执行测试然后自行清理,将所有测试重新置于干净状态的问题。
请记住,在某些情况下,标准清理例程(例如@Before
和@After
)是不够的。我前一段时间遇到的一个问题是在一组数据库测试中:我在数据库中添加记录作为测试的一部分,需要专门删除我刚刚添加的记录。
因此,有时您需要添加特定的清理代码才能恢复到原始状态。
答案 1 :(得分:1)
似乎您在假设执行方法的顺序是固定的情况下构建了测试套件。这是错误的 - JUnit不保证测试方法的执行顺序,所以你不应该依赖它。
这是设计 - 单元测试应该完全相互独立。为了保证这一点,JUnit为测试类创建了一个独特的新实例,用于执行每个测试方法。因此,无论您在一种方法中设置的属性如何,都将在下一种方法中丢失。
如果您有常见的测试设置/拆卸代码,则应将其放入单独的方法中,并使用@Before
/ @After
进行注释。这些在每种测试方法之前和之后执行。
更新:你写了
在@BeforeClass
中的每个测试之前清除数据库
如果这不是拼写错误,这可能是您问题的根源。应使用@Before
方法清除数据库 - @BeforeClass
每个类只运行一次。
答案 2 :(得分:0)
请谨慎使用@BeforeClass
一劳永逸地设置内容,@Before
在每次单独测试之前设置内容。并注意实例变量。
如果您可以发布一个简单的错误示例,我们可能会更具体地提供帮助。