JUNIT:对于大量测试类只运行一次安装

时间:2013-09-02 13:30:46

标签: java database unit-testing junit package

我有一个课程,我用它作为单元测试的基础。在这个类中,我初始化我的测试的整个环境,设置数据库映射,在多个表中输入许多数据库记录等。该类有一个带有@BeforeClass注释的方法来进行初始化。接下来,我使用@Test方法的特定类扩展该类。

我的问题是,由于前一类对于所有这些测试类完全相同,我如何确保它们仅针对所有测试运行一次。 一个简单的解决方案是我可以将所有测试保持在一个类中。但是,测试的数量很大,它们也是根据功能头分类的。所以他们位于不同的班级。但是,由于它们需要完全相同的设置,因此它们继承了@BeforeClass。因此,每个测试类至少完成一次整个设置,总共花费的时间比我想要的多。

但是,我可以将它们全部放在一个包下的各种子包中,因此如果有办法,我可以为该包中的所有测试运行一次设置,那就太棒了。

6 个答案:

答案 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对每个类执行一次操作。