首页 文章

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

提问于
浏览
0

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

到目前为止,它在 class 上工作得很好 .

@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
    }
}

到目前为止,它在 class 上工作得很好 .

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

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

....但这个原则如何扩展到套件级别?

我想在套件中的所有课程之前运行@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测试,同时保持会话级别setUp和tearDown进程?

2 回答

  • 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();
    }
    
  • 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
        }
    }
    

    并非所有测试都需要初始化堆栈,但那些将会从此基类中获取并且它将正确处理init . 希望有所帮助 .

相关问题