探索JUnit4擴展:使用Rule
在上一篇文章《探索JUnit4擴展:擴展Runner》中,討論了一種擴展JUnit4的方式,即,直接修改Test Runner的實現(xiàn)(BlockJUnit4ClassRunner)。但這種方法顯然不便于靈活地添加或刪除擴展功能。本文將使用JUnit4.7才開始引入的擴展方式--Rule來實現(xiàn)相同的擴展功能。(2010.12.25***更新)
1. Rule
Rule是JUnit4.7才開始提供的一種擴展方式,它能夠替代大部分已有的Runner擴展。JUnit包含兩種Rule Annotation:@ClassRule與@Rule。@ClassRule應(yīng)用于測試類中的靜態(tài)變量,而@Rule應(yīng)用于成員變量;相同地是,這些變量必須是TestRule接口的實例,且訪問修飾符必須為public。
在上篇博文中,對BlockJUnit4ClassRunner進行了擴展,被擴展的方法是methodBlock,現(xiàn)在我們來看看該方法體中的代碼:
- protected Statement methodBlock(FrameworkMethod method) {
 - Object test;
 - try {
 - test= new ReflectiveCallable() {
 - @Override
 - protected Object runReflectiveCall() throws Throwable {
 - return createTest();
 - }
 - }.run();
 - } catch (Throwable e) {
 - return new Fail(e);
 - }
 - Statement statement= methodInvoker(method, test);
 - statement= possiblyExpectingExceptions(method, test, statement);
 - statement= withPotentialTimeout(method, test, statement);
 - statement= withBefores(method, test, statement);
 - statement= withAfters(method, test, statement);
 - statement= withRules(method, test, statement);
 - return statement;
 - }
 
但在BlockJUnit4ClassRunner中,possiblyExpectingExceptions(),withPotentialTimeout(),withBefores()和withAfters()都已經(jīng)被標(biāo)注為過時,JUnit建議使用Rule來替代這些方法的功能。
2. TestLogRule
如第1節(jié)所述,Rule Annotation要作用于TestRule接口的實例,那么就要先創(chuàng)建一個TestRule的實現(xiàn)類。
- public class TestLogRule implements TestRule {
 - private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss_SSS");
 - @Override
 - public Statement apply(Statement base, Description description) {
 - TestLogger testLogger = description.getAnnotation(TestLogger.class);
 - if (testLogger != null) {
 - StringBuilder log = new StringBuilder(format.format(new Date()));
 - log.append(" ").append(description.getClassName()).append("#")
 - .append(description.getMethodName()).append(": ")
 - .append(testLogger.log());
 - System.out.println(log.toString());
 - }
 - return base;
 - }
 - }
 
如上所示,TestLogRule與上篇博文中的LoggedRunner的代碼有許多相同之處,功能則都是打印出指定的日志,每行日志又以當(dāng)時的執(zhí)行時間與完整方法名作為前綴。
3. 使用Rule的CalculatorTest
下面是新的測試類CalculatorTest,它將不使用BlockJUnit4ClassRunner的擴展LoggedRunner作為測試執(zhí)行器,所以該類沒有使用@RunWith(LoggedRunner.class),那么在執(zhí)行該測試類時仍然會使用BlockJUnit4ClassRunner。
- public class CalculatorTest {
 - private static Calculator calculator = null;
 - @Rule
 - public TestLogRule testLogRule = new TestLogRule();
 - @BeforeClass
 - public static void createCalculator() {
 - calculator = new Calculator();
 - }
 - @Test
 - @TestLogger(log = "a simple division")
 - public void simpleDivide() {
 - int value = calculator.divide(8, 2);
 - Assert.assertTrue(value == 4);
 - }
 - @Test(expected = ArithmeticException.class)
 - @TestLogger(log = "divided by zero, and an ArithmeticException thrown.")
 - public void dividedByZero() {
 - calculator.divide(8, 0);
 - }
 - }
 
與上篇博文中的CalculatorTest相比,本文中的CalculatorTest除了沒有使用LoggedRunner之外,還多了兩行代碼:
- @Rule
 - public TestLogRule testLogRule = new TestLogRule();
 
在執(zhí)行單元測試方法之前,BlockJUnit4ClassRunner會調(diào)用TestRule/TestLogRule中的apply()方法,即,會先打印出日志內(nèi)容。
4. 小結(jié)
使用Rule對JUnit進行擴展,能夠避免對默認(rèn)Runner的擴展,為測試類添加或移除Rule十分方便,而且Rule實現(xiàn)類本身也能很方便地被復(fù)用。
原文鏈接:http://www.blogjava.net/jiangshachina/archive/2011/12/24/366801.html
【編輯推薦】















 
 
 





 
 
 
 