在套件中使用@BeforeClass @Before编写JUnit测试

时间:2018-10-16 12:21:10

标签: java junit junit4

我正在使用JUnit 4来测试带有内存数据库的后端系统。我正在使用 @BeforeClass @Before @After @AfterClass

到目前为止,它在课堂上一直很好。

@BeforeClass 包含很慢的数据库设置,但每个测试会话只需完成一次。

@Before 只是将板擦干净以进行下一个测试。非常快。

我的测试看起来像这样:

class CompanyTest  {

    @BeforeClass
    public static void beforeAll() throws Exception {
        BeforeAll.run(); //Setup In Memory Database!!! Very time intensive!!!
    }
    @Before
    public void beforeTest() throws Exception {
        BeforeTest.run(); //Setup data in database. Relatively quick
    }


    @Test
    public void testCreateCompany() throws Exception {
        ///...
    }
    @Test
    public void testDeleteCompany() throws Exception {
        ///...
    }
    @Test
    public void testAdminCompany() throws Exception {
        ///...
    }


    @After
    public void afterTest() {
        AfterTest.run(); //clear data
    }
    @AfterClass
    public static void afterAll() throws Exception {
        AfterAll.run(); //tear down database
    }
}

到目前为止,它在课堂上一直很好。

我可以右键单击(在Eclipse中)单个测试,它将运行 @BeforeClass ,然后运行 @Before

我也可以在类本身上单击(在Eclipse中),它将只运行一次 @BeforeClass ,然后在每次测试前运行 @Before

....但是该原则如何扩展到套件级别?

我想在我的Suite中的所有类之前运行@BeforeClass。如果我这样写我的套件:

@Suite.SuiteClasses({ CompanyTest.class, CustomerTest.class, SomeOtherTest.class, })

public class AllTests {

    @BeforeClass
    public static void beforeAll() throws Exception {
        BeforeAll.run();
    }

    @AfterClass
    public static void afterAll() throws Exception {
        AfterAll.run();
    }
}

...我需要从所有测试类中删除@BeforeClass。这很烦人,因为我有很多测试类,并且我不想删除@BeforeClass,因为我想单独测试它们。

我基本上要说的是:

是否有一种简单的方法(在IDE中单击鼠标)可以在(a)方法级别,(b)类级别和(c)套件级别测试JUnit测试,同时保持会话级别设置和拆卸过程?

2 个答案:

答案 0 :(得分:1)

因此,我有一个类似的问题(数据库初始化,连接池,缓存的数据等),在运行任何和所有测试之前需要完成一次。通常在应用程序服务器启动时完成。对于需要这样做的测试,我添加了一个基类:

public class BaseInitializedTest {
    private boolean isInitialized;

    @BeforeClass
    public static void init() {
        doOnetimeInit();

        // Do other per unique class initialization here
    }

    private static synchronized void doOnetimeInit() {
        if (!isInitialized) {
            // Do you one time init here

            isInitialized = true;
        }
    }

    @AfterClass
    public static void deinit() {
        // Cleanup
    }
}

然后是需要初始化的测试:

public class SomethingTest extends BaseInitializedTest {
    @Test
    public testSomething() {
        // Your test here
    }
}

并非所有测试都需要初始化堆栈,但是那些测试会从该基类中进行初始化,并且将正确处理初始化。希望有帮助。

答案 1 :(得分:1)

您需要的是,全局状态是通过不同的入口点进行管理的。在您的BeforeAll或AfterAll类中,您可以保留静态引用,即AtomicBoolean来跟踪您是否已经执行了它。

现在的问题-对于beforeAll和afterAll具有两个单独的类-哪个类应负责该标志。

因此,我建议您定义一个Rule,其中包含所有用于设置和拆卸的逻辑(基本上是BeforeAll和AfterAll的所有代码),并管理用于跟踪初始化的全局状态。

基本上类似

class MyRule implements TestRule {
    static final AtomicBoolean INITIALIZED = new AtomicBoolean();

    @Override
    public Statement apply(final Statement base, final Description description) {

        return new Statement() {

            @Override
            public void evaluate() throws Throwable {
                boolean needsTearDown = false;
                try {
                    if (INITIALIZED.compareAndSet(false, true)) {
                        BeforeAll.run();
                        needsTearDown = true;
                    }
                    base.evaluate();
                } finally {
                    if (needsTearDown) {
                        AfterAll.run();
                        INITIALIZED.set(false);
                    }
                }
            }
        };
    }
}

然后在您的测试和套件中添加

class YourTestOrSuite {

  @ClassRule
  public static MyRule rule = new MyRule();
}