John Jiang

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

             :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          探索JUnit4擴(kuò)展:擴(kuò)展Runner
          在使用JUnit的過程中,大家可能會對JUnit進(jìn)行一些擴(kuò)展。本文中的示例為JUnit4定義了一個(gè)新的Annotation,并相應(yīng)地對已有的Runner進(jìn)行擴(kuò)展,使其能夠解析新引入的Annotation。(2011.12.25最后更新)

          本文臆造了一個(gè)示例,會在執(zhí)行單元測試方法之前,自動地為單元測試方法打印日志。該示例會為JUnit定義一個(gè)新的Annotation用于指定要打印的日志內(nèi)容,并對JUnit默認(rèn)提供的Runner實(shí)現(xiàn)BlockJUnit4ClassRunner進(jìn)行擴(kuò)展,使其能夠識別這個(gè)新的Annotation。

          1. 定義Annotation
              TestLogger是一個(gè)作用于方法的Annotation,它只有一個(gè)屬性,用于指定日志的內(nèi)容,其代碼如下所示,
          @Target({ ElementType.METHOD })
          @Retention(RetentionPolicy.RUNTIME)
          public @interface TestLogger {
              
          public String log() default "";
          }

          2. 擴(kuò)展Runner
              JUnit提供了若干個(gè)Runner的實(shí)現(xiàn),如BlockJUnit4ClassRunner,Suite,其中BlockJUnit4ClassRunner用來執(zhí)行單個(gè)測試用例類。LoggedRunner將擴(kuò)展BlockJUnit4ClassRunner,覆寫其中的methodBlock()方法。新的methodBlock()方法會在一開始試圖獲取被執(zhí)行測試方法中的TestLogger Annotation,如果存在的話,就會打印出指定的日志,每行日志以當(dāng)時(shí)的執(zhí)行時(shí)間與完整方法名作為前綴。該類的代碼如下所示,
          public class LoggedRunner extends BlockJUnit4ClassRunner {

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

              
          public LoggedRunner(Class<?> klass) throws InitializationError {
                  
          super(klass);
              }

              @Override
              
          protected Statement methodBlock(FrameworkMethod method) {
                  Method classMethod 
          = method.getMethod();
                  TestLogger loggerAnnotation 
          = classMethod.getAnnotation(TestLogger.class);
                  
          if (loggerAnnotation != null) {
                      StringBuilder log 
          = new StringBuilder(format.format(new Date()));
                      log.append(
          " ").append(classMethod.getDeclaringClass().getName())
                              .append(
          "#").append(classMethod.getName()).append("")
                              .append(loggerAnnotation.log());
                      System.out.println(log.toString());
                  }

                  
          return super.methodBlock(method);
              }
          }

          3. 應(yīng)用程序
              Calculator是一個(gè)簡單的應(yīng)用程序,其中定義了一個(gè)除法方法,代碼如下所示,
          public class Calculator {

              
          public int divide(int a, int b) {
                  
          return a / b;
              }
          }

          4. 單元測試程序
              CalculatorTest是一個(gè)簡單的單元測試程序,它會使用兩種方式對Calculator中的divide()方法進(jìn)行單元測試。其代碼如下所示,
          @RunWith(LoggedRunner.class)
          public class CalculatorTest {

              
          private static Calculator calculator = null;

              @BeforeClass
              
          public static void createCalculator() {
                  calculator 
          = new Calculator();
              }

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

          值得注意的是,CalculatorTest特別指定LoggedRunner作為測試執(zhí)行器(@RunWith(LoggedRunner.class));同時(shí),每個(gè)單元測試方法,simpleDivide()與dividedByZero(),都使用了Annotation TestLogger,為其指定日志內(nèi)容。當(dāng)執(zhí)行上述單元測試時(shí),會自動地打印出如下形式的日志內(nèi)容:
          2011-12-13_23:48:38_218 test.CalculatorTest#simpleDivide: a simple division
          2011-12-13_23:48:38_218 test.CalculatorTest#dividedByZero: divided by zero, and an ArithmeticException thrown.

          5. 小結(jié)
          通過對BlockJUnit4ClassRunner的擴(kuò)展,可以讓JUnit在運(yùn)行測試用例時(shí)做一些額外的工作。但這種直接修改默認(rèn)Test Runner的方式并不被提倡,在下一篇文章中將會介紹使用Test Rule來達(dá)到相同的擴(kuò)展目的。
           
          posted on 2011-12-14 00:01 John Jiang 閱讀(3058) 評論(4)  編輯  收藏 所屬分類: JavaUnitTestJUnit 、原創(chuàng)

          評論

          # re: 初探JUnit4擴(kuò)展(原)[未登錄] 2011-12-15 09:58 bruce
          你好,請問一下,如果我要攔截失敗的異常,要重寫B(tài)lockJUnit4ClassRunner哪個(gè)方法呢?  回復(fù)  更多評論
            

          # re: 初探JUnit4擴(kuò)展(原) 2011-12-15 21:58 Sha Jiang
          @bruce
          可以看看對TestRule/ExpectedException的使用  回復(fù)  更多評論
            

          # re: 初探JUnit4擴(kuò)展(原) 2011-12-20 19:57 來如風(fēng)
          請問,這個(gè)和我直接在方法里logger.info()有啥區(qū)別!!  回復(fù)  更多評論
            

          # re: 初探JUnit4擴(kuò)展(原) 2011-12-21 20:12 Sha Jiang
          @來如風(fēng)
          你是指在單元測試方法中直接使用Logger工具?
          可能是沒什么區(qū)別,甚至于在測試方法中直接使用Logger會更好些。
          但在此處,用這個(gè)例子只是為了說明一種擴(kuò)展JUnit的方式罷了。  回復(fù)  更多評論
            

          主站蜘蛛池模板: 永靖县| 扬州市| 温泉县| 临海市| 寿阳县| 武强县| 平阴县| 江城| 淮阳县| 宣威市| 柘荣县| 新兴县| 乡城县| 宁德市| 上饶县| 金乡县| 措美县| 铜梁县| 尼玛县| 四会市| 老河口市| 郴州市| 泗阳县| 潞城市| 晋江市| 务川| 兴宁市| 扬中市| 阿勒泰市| 永善县| 荆门市| 岳普湖县| 理塘县| 徐汇区| 惠东县| 梁平县| 游戏| 吕梁市| 平湖市| 鲁山县| 信宜市|