John Jiang

          a cup of Java, cheers!
          https://github.com/johnshajiang/blog

             :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          探索JUnit4擴展:深入Rule
          本文是"探索JUnit4擴展"系列中的第三篇,將進一步探究Rule的應用,展示如何使用Rule來替代@BeforeClass,@AfterClass,@Before和@After的功能。(2012.01.04最后更新)

          在本系列的第二篇《探索JUnit4擴展:應用Rule》中提到,可以使用Rule替代現有的大部分Runner擴展,而且也不提倡對Runner中的withBefores(),withAfters()等方法進行擴展。本文將介紹如何使用Rule去實現@Before,@After和@BeforeClass的相同功能。

          1. BaseRule
              首先要創建一個較通用的TestRule實現BaseRule,它會釋放出兩個擴展點,一個在執行測試方法之前,before();另一個在執行測試方法之后after()。下面是該類的代碼,
          public abstract class BaseRule implements TestRule {

              @Override
              
          public Statement apply(Statement base, Description description) {
                  
          return new RuleStatement(base, description);
              }

              
          private class RuleStatement extends Statement {

                  
          private Statement base = null;

                  
          private Description description = null;

                  
          private RuleStatement(Statement base, Description description) {
                      
          this.base = base;
                      
          this.description = description;
                  }

                  @Override
                  
          public void evaluate() throws Throwable {
                      before(base, description);
                      
          try {
                          base.evaluate();
                      } 
          finally {
                          after(base, description);
                      }
                  }
              }

              
          protected void before(Statement base, Description description) throws Throwable {

              }

              
          protected void after(Statement base, Description description) {

              }
          }
          如果對JUnit4的源代碼略有認知,可能會發現BaseRule與JUnit4提供的TestRule實現ExternalResource代碼相似。關鍵的不同之處是,BaseRule中的before()與after()方法都提供了Statement與Description類型的參數,這使得它能夠完成更復雜的工作。

          2. CalculatorTest
              本文使用的CalculatorTest將不使用@BeforeClass,@Before和@After,而會創建兩個BaseRule的實例:一個用于替代@BeforeClass和@AfterClass(本系列目前還未使用過@AfterClass),另一個則替代@Before和@After。
          public class CalculatorTest {

              
          private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss_SSS");

              
          private static Calculator calculator = null;

              @ClassRule
              
          public static BaseRule classRule = new BaseRule() {

                  
          protected void before(Statement base, Description description) throws Throwable {
                      calculator 
          = new Calculator();
                  };
              };

              @Rule
              
          public BaseRule rule = new BaseRule() {

                  
          protected void before(Statement base, Description description) throws Throwable {
                      printBeforeLog(description);
                  };

                  
          protected void after(Statement base, Description description) {
                      printAfterLog(description);
                  };

                  
          private void printBeforeLog(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());
                      }
                  }

                  
          private void printAfterLog(Description description) {
                      StringBuilder log 
          = new StringBuilder(format.format(new Date()));
                      log.append(
          " ").append(description.getClassName()).append("#")
                              .append(description.getMethodName()).append(
          " end");
                      System.out.println(log.toString());
                  }
              };

              @Test
              @TestLogger(log 
          = "a simple division")
              
          public void simpleDivide() {
                  
          int value = calculator.divide(82);
                  Assert.assertTrue(value 
          == 4);
              }

              @Test(expected 
          = ArithmeticException.class)
              @TestLogger(log 
          = "divided by zero, and an ArithmeticException thrown.")
              
          public void dividedByZero() {
                  calculator.divide(
          80);
              }
          }
          值得注意的是,classRule是靜態變量,它使用@ClassRule Annotation,將替代@BeforeClass和@AfterClass;而rule是成員變量,它使用@Rule Annotation,將替代@Before和@After。與之前文章不同的是,此處不僅會在執行測試方法之前打印指定內容的日志(printBeforeLog()),還會在執行測試方法之后打印一條固定格式的日志(printAfterLog()),用于指示該測試方法已經執行完畢了。

          3. 小結
              使用Rule可以替代絕大部分的Runner擴展,而且特定的Rule實現可以被復用,也易于添加或移除Rule實例,這些都大大地提高了靈活性。值得注意地是,本文雖然使用Rule代替了@BeforeClass,@AfterClass,@Before和@After的功能,但并不意味著就應當這么做。就我個人所想,將傳統的Fixture功能交由@BeforeClass,@AfterClass,@Before和@After實現,仍然是一種不錯的選擇。
          posted on 2012-01-04 00:13 John Jiang 閱讀(2364) 評論(3)  編輯  收藏 所屬分類: JavaUnitTestJUnit原創

          評論

          # re: 探索JUnit4擴展:深入Rule(原)[未登錄] 2013-06-05 16:02 eric
          太好了,解決了我很多的問題,謝謝,學習了  回復  更多評論
            

          # re: 探索JUnit4擴展:深入Rule(原) 2013-06-05 21:51 Sha Jiang
          @eric
          了解到內部實現之后,這些所謂的擴展設計似乎也傻傻滴@_@  回復  更多評論
            

          主站蜘蛛池模板: 博湖县| 沧源| 大渡口区| 资溪县| 安宁市| 公安县| 天水市| 荥经县| 准格尔旗| 东方市| 泾阳县| 清河县| 高碑店市| 沅陵县| 岐山县| 凯里市| 绿春县| 丰都县| 海南省| 盐亭县| 京山县| 杭锦旗| 临汾市| 山西省| 普安县| 三台县| 铜陵市| 西丰县| 宾川县| 广丰县| 静海县| 武鸣县| 大庆市| 新丰县| 宁安市| 南雄市| 会理县| 张家川| 文安县| 溧水县| 阳谷县|