我有一个课程,我用它作为单元测试的基础。在这个类中,我初始化我的测试的整个环境,设置数据库映射,在多个表中输入许多数据库记录等。该类有一个带有@BeforeClass注释的方法来进行初始化。接下来,我使用@Test方法的特定类扩展该类。
我的问题是,由于前一类对于所有这些测试类完全相同,我如何确保它们仅针对所有测试运行一次。 一个简单的解决方案是我可以将所有测试保持在一个类中。但是,测试的数量很大,它们也是根据功能头分类的。所以他们位于不同的班级。但是,由于它们需要完全相同的设置,因此它们继承了@BeforeClass。因此,每个测试类至少完成一次整个设置,总共花费的时间比我想要的多。
但是,我可以将它们全部放在一个包下的各种子包中,因此如果有办法,我可以为该包中的所有测试运行一次设置,那就太棒了。答案 0 :(得分:17)
使用JUnit4测试套件,您可以执行以下操作:
@RunWith(Suite.class)
@Suite.SuiteClasses({ Test1IT.class, Test2IT.class })
public class IntegrationTestSuite
{
@BeforeClass
public static void setUp()
{
System.out.println("Runs before all tests in the annotation above.");
}
@AfterClass
public static void tearDown()
{
System.out.println("Runs after all tests in the annotation above.");
}
}
然后你运行这个类就像运行一个普通的测试类一样,它将运行你所有的测试。
答案 1 :(得分:7)
JUnit不支持这一点,你必须使用标准的Java解决方案来实现单例:将公共设置代码移动到静态代码块中,然后在这个类中调用一个空方法:
static {
...init code here...
}
public static void init() {} // Empty method to trigger the execution of the block above
确保所有测试都调用init()
,例如我将其放入@BeforeClass
方法。或者将静态代码块放入共享基类中。
或者,使用全局变量:
private static boolean initialize = true;
public static void init() {
if(!initialize) return;
initialize = false;
...init code here...
}
答案 2 :(得分:1)
为所有测试创建一个基类:
public class BaseTest {
static{
/*** init code here ***/
}
}
并且每个测试都应该继承它:
public class SomeTest extends BaseTest {
}
答案 3 :(得分:1)
您可以使用BaseTest
方法创建一个@BeforeClass
类,然后让所有其他测试继承。这样,当构造每个测试对象时,@BeforeClass
被执行。
同样避免对所有测试套件执行一次,因为所有测试用例都应该是独立的。 @BeforeClass
每个测试用例只应执行一次,而不是测试套件。
答案 4 :(得分:0)
如果您可以容忍在项目中添加弹簧测试,或者您已经在使用它,那么一个好的方法是使用此处描述的技术:How to load DBUnit test data once per case with Spring Test
答案 5 :(得分:0)
不确定是否有人仍在使用JUnit并尝试在不使用Spring Runner(也就是没有弹簧集成)的情况下修复它。 TestNG具有此功能。但这是一个基于JUnit的解决方案。
为每个线程操作创建一个RunOnce。这将维护已运行该操作的类列表。
public class RunOnceOperation {
private static final ThreadLocal t = new ThreadLocal();
public void run(Function f) {
if (t.get() == null) {
t.set(Arrays.asList(getClass()));
f.apply(0);
} else {
if (!((List) t.get()).contains(getClass())) {
((List) t.get()).add(getClass());
f.apply(0);
}
}
}
}
返回单元测试
@Before
public beforeTest() {
operation.run(new Function<Integer, Void>() {
@Override
public Void apply(Integer t) {
checkBeanProperties();
return null;
}
});
}
private void checkBeanProperties() {
//I only want to check this once per class.
//Also my bean check needs instance of the class and can't be static.
}
My function interface is like this:
interface Function<I,O> {
O apply(I i);
}
使用这种方式时,您可以使用ThreadLocal对每个类执行一次操作。