探索JUnit4擴展:擴展Runner
在使用JUnit的過程中,大家可能會對JUnit進(jìn)行一些擴展。本文中的示例為JUnit4定義了一個新的Annotation,并相應(yīng)地對已有的Runner進(jìn)行擴展,使其能夠解析新引入的Annotation。(2011.12.25***更新)
本文臆造了一個示例,會在執(zhí)行單元測試方法之前,自動地為單元測試方法打印日志。該示例會為JUnit定義一個新的Annotation用于指定要打印的日志內(nèi)容,并對JUnit默認(rèn)提供的Runner實現(xiàn)BlockJUnit4ClassRunner進(jìn)行擴展,使其能夠識別這個新的Annotation。
1. 定義Annotation
TestLogger是一個作用于方法的Annotation,它只有一個屬性,用于指定日志的內(nèi)容,其代碼如下所示,
- @Target({ ElementType.METHOD })
- @Retention(RetentionPolicy.RUNTIME)
- public @interface TestLogger {
- public String log() default "";
- }
2. 擴展Runner
JUnit提供了若干個Runner的實現(xiàn),如BlockJUnit4ClassRunner,Suite,其中BlockJUnit4ClassRunner用來執(zhí)行單個測試用例類。LoggedRunner將擴展BlockJUnit4ClassRunner,覆寫其中的methodBlock()方法。新的methodBlock()方法會在一開始試圖獲取被執(zhí)行測試方法中的TestLogger Annotation,如果存在的話,就會打印出指定的日志,每行日志以當(dāng)時的執(zhí)行時間與完整方法名作為前綴。該類的代碼如下所示,
- 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是一個簡單的應(yīng)用程序,其中定義了一個除法方法,代碼如下所示,
- public class Calculator {
- public int divide(int a, int b) {
- return a / b;
- }
- }
4. 單元測試程序
CalculatorTest是一個簡單的單元測試程序,它會使用兩種方式對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(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特別指定LoggedRunner作為測試執(zhí)行器(@RunWith(LoggedRunner.class));同時,每個單元測試方法,simpleDivide()與dividedByZero(),都使用了Annotation TestLogger,為其指定日志內(nèi)容。當(dāng)執(zhí)行上述單元測試時,會自動地打印出如下形式的日志內(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的擴展,可以讓JUnit在運行測試用例時做一些額外的工作。但這種直接修改默認(rèn)Test Runner的方式并不被提倡,在下一篇文章中將會介紹使用Test Rule來達(dá)到相同的擴展目的。
原文鏈接:http://www.blogjava.net/jiangshachina/archive/2011/12/14/366289.html
【編輯推薦】