??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美日韩精品免费,亚洲国产日韩a在线播放,99久久伊人http://www.aygfsteel.com/jiangshachina/category/32067.html同是Java爱好者,盔R何必曾相识Q?lt;br>    a cup of Java, cheers!zh-cnWed, 04 Jan 2012 20:59:08 GMTWed, 04 Jan 2012 20:59:08 GMT60探烦JUnit4扩展Q深入Rule(?http://www.aygfsteel.com/jiangshachina/archive/2012/01/04/367802.htmlSha JiangSha JiangTue, 03 Jan 2012 16:13:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2012/01/04/367802.htmlhttp://www.aygfsteel.com/jiangshachina/comments/367802.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2012/01/04/367802.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/367802.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/367802.html
探烦JUnit4扩展Q深入Rule
本文?探烦JUnit4扩展"pd中的W三,进一步探IRule的应用,展示如何使用Rule来替代@BeforeClassQ@AfterClassQ@Before和@After的功能?2012.01.04最后更?

在本pd的第二篇《探索JUnit4扩展Q应用Rule?/a>中提刎ͼ可以使用Rule替代现有的大部分Runner扩展Q而且也不提倡对Runner中的withBefores()QwithAfters(){方法进行扩展。本文将介绍如何使用Ruled现@BeforeQ@After和@BeforeClass的相同功能?/span>

1. BaseRule
    首先要创Z个较通用的TestRule实现BaseRuleQ它会释攑և两个扩展点,一个在执行试Ҏ之前Qbefore()Q另一个在执行试Ҏ之后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的源代码略有认知Q可能会发现BaseRule与JUnit4提供的TestRule实现ExternalResource代码怼。关键的不同之处是,BaseRule中的before()与after()Ҏ都提供了Statement与Descriptioncd的参敎ͼq得它能够完成更复杂的工作?/span>

2. CalculatorTest
    本文使用的CalculatorTest不使用@BeforeClassQ@Before和@AfterQ而会创徏两个BaseRule的实例:一个用于替代@BeforeClass和@AfterClass(本系列目前还未用过@AfterClass)Q另一个则替代@Before和@After?/span>
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);
    }
}
值得注意的是QclassRule是静态变量,它用@ClassRule AnnotationQ将替代@BeforeClass和@AfterClassQ而rule是成员变量,它用@Rule AnnotationQ将替代@Before和@After。与
之前文章不同的是Q此处不仅会在执行测试方法之前打印指定内容的日志(printBeforeLog())Q还会在执行试Ҏ之后打印一条固定格式的日志(printAfterLog())Q用于指C试Ҏ已经执行完毕了?/span>

3. 结
    使用Rule可以替代l大部分的Runner扩展Q而且特定的Rule实现可以被复用,也易于添加或U除Rule实例Q这些都大大地提高了灉|性。值得注意地是Q本文虽然用Rule代替了@BeforeClassQ@AfterClassQ@Before和@After的功能,但ƈ不意味着应当这么做。就我个人所惻I传l的Fixture功能交由@BeforeClassQ@AfterClassQ@Before和@After实现Q仍然是一U不错的选择?/span>


Sha Jiang 2012-01-04 00:13 发表评论
]]>
探烦JUnit4扩展Q应用Rule(?http://www.aygfsteel.com/jiangshachina/archive/2011/12/24/366801.htmlSha JiangSha JiangSat, 24 Dec 2011 15:26:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2011/12/24/366801.htmlhttp://www.aygfsteel.com/jiangshachina/comments/366801.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2011/12/24/366801.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/366801.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/366801.html
探烦JUnit4扩展Q用Rule
在上一文?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">《探索JUnit4扩展Q扩展Runner?/a>中,讨论了一U扩展JUnit4的方式,卻I直接修改Test Runner的实?BlockJUnit4ClassRunner)。但q种Ҏ昄不便于灵zdd或删除扩展功能。本文将使用JUnit4.7才开始引入的扩展方式--Rule来实现相同的扩展功能?2010.12.25最后更?

1. Rule
Rule是JUnit4.7才开始提供的一U扩展方式,它能够替代大部分已有的Runner扩展。JUnit包含两种Rule AnnotationQ@ClassRule与@Rule。@ClassRule应用于测试类中的静态变量,而@Rule应用于成员变量;相同地是Q这些变量必LTestRule接口的实例,且访问修饰符必须为public?br />?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">上篇博文中,对BlockJUnit4ClassRunnerq行了扩展,被扩展的Ҏ是methodBlockQ现在我们来看看该方法体中的代码Q?br />
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()QwithPotentialTimeout()QwithBefores()和withAfters()都已l被标注ӞJUnit使用Rule来替代这些方法的功能?br />
2. TestLogRule
如第1节所qͼRule Annotation要作用于TestRule接口的实例,那么p先创Z个TestRule的实现类?br />
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;
    }
}
如上所C,TestLogRule?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">上篇博文中的LoggedRunner的代码有许多相同之处Q功能则都是打印出指定的日志Q每行日志又以当时的执行旉与完整方法名作ؓ前缀?br />
3. 使用Rule的CalculatorTest
下面是新的测试类CalculatorTestQ它不使用BlockJUnit4ClassRunner的扩展LoggedRunner作ؓ试执行器,所以该cL有用@RunWith(LoggedRunner.class)Q那么在执行该测试类时仍然会使用BlockJUnit4ClassRunner?br />
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(82);
        Assert.assertTrue(value 
== 4);
    }

    @Test(expected 
= ArithmeticException.class)
    @TestLogger(log 
= "divided by zero, and an ArithmeticException thrown.")
    
public void dividedByZero() {
        calculator.divide(
80);
    }
}
?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">上篇博文中的CalculatorTest相比Q本文中的CalculatorTest除了没有使用LoggedRunner之外Q还多了两行代码
@Rule
public TestLogRule testLogRule = new TestLogRule();
在执行单元测试方法之前,BlockJUnit4ClassRunner会调用TestRule/TestLogRule中的apply()ҎQ即Q会先打印出日志内容?br />
4. 结
使用Rule对JUnitq行扩展Q能够避免对默认Runner的扩展,为测试类d或移除Rule十分方便Q而且Rule实现cLw也能很方便地被复用。在下一博?/a>中将q一步探索Rule的应用?/div>

Sha Jiang 2011-12-24 23:26 发表评论
]]>
探烦JUnit4扩展Q扩展Runner(?http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.htmlSha JiangSha JiangTue, 13 Dec 2011 16:01:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.htmlhttp://www.aygfsteel.com/jiangshachina/comments/366289.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html#Feedback4http://www.aygfsteel.com/jiangshachina/comments/commentRss/366289.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/366289.html
探烦JUnit4扩展Q扩展Runner
在用JUnit的过E中Q大家可能会对JUnitq行一些扩展。本文中的示例ؓJUnit4定义了一个新的AnnotationQƈ相应地对已有的Runnerq行扩展Q其能够解析新引入的Annotation?2011.12.25最后更?

本文臆造了一个示例,会在执行单元试Ҏ之前Q自动地为单元测试方法打印日志。该CZ会ؓJUnit定义一个新的Annotation用于指定要打印的日志内容Qƈ对JUnit默认提供的Runner实现BlockJUnit4ClassRunnerq行扩展Q其能够识别这个新的Annotation?br />
1. 定义Annotation
    TestLogger是一个作用于Ҏ的AnnotationQ它只有一个属性,用于指定日志的内容,其代码如下所C,
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface TestLogger {
    
public String log() default "";
}

2. 扩展Runner
    JUnit提供了若q个Runner的实玎ͼ如BlockJUnit4ClassRunnerQSuiteQ其中BlockJUnit4ClassRunner用来执行单个试用例cRLoggedRunner扩展BlockJUnit4ClassRunnerQ覆写其中的methodBlock()Ҏ。新的methodBlock()Ҏ会在一开始试图获取被执行试Ҏ中的TestLogger AnnotationQ如果存在的话,׃打印出指定的日志Q每行日志以当时的执行时间与完整Ҏ名作为前~。该cȝ代码如下所C,
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. 应用E序
    Calculator是一个简单的应用E序Q其中定义了一个除法方法,代码如下所C,
public class Calculator {

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

4. 单元试E序
    CalculatorTest是一个简单的单元试E序Q它会用两U方式对Calculator中的divide()Ҏq行单元试。其代码如下所C,
@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);
    }
}

值得注意的是QCalculatorTest特别指定LoggedRunner作ؓ试执行?@RunWith(LoggedRunner.class))Q同Ӟ每个单元试ҎQsimpleDivide()与dividedByZero()Q都使用了Annotation TestLoggerQؓ其指定日志内宏V当执行上述单元试Ӟ会自动地打印出如下Ş式的日志内容Q?br />
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. 结
通过对BlockJUnit4ClassRunner的扩展,可以让JUnit在运行测试用例时做一些额外的工作。但q种直接修改默认Test Runner的方式ƈ不被提倡,?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/24/366801.html">下一文?/a>中将会介l用Test Rule来达到相同的扩展目的?br /> 

Sha Jiang 2011-12-14 00:01 发表评论
]]>
何时~写单元试Q??http://www.aygfsteel.com/jiangshachina/archive/2008/06/09/206812.htmlSha JiangSha JiangMon, 09 Jun 2008 12:55:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2008/06/09/206812.htmlhttp://www.aygfsteel.com/jiangshachina/comments/206812.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2008/06/09/206812.html#Feedback2http://www.aygfsteel.com/jiangshachina/comments/commentRss/206812.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/206812.html何时~写单元试Q?/span>
    是在~写一个方法之前就~写它的单元试Q还是在写完q个ҎQ甚x整个cM后才~写单元试呢?John Ferguson Smart[1]在他?a >blog中再ơ提Zq个问题QƈҎ自己的经验给Z一些徏议?2008.06.10最后更?

    都别书生意气了。在你编写一个方法之前或是之后编写单元测?-Ҏ我的l验Q只要你在编写代码的几乎同时p虑q编写单元测试程序,那么q就无关紧要了。过后再q回?或者根本就不回?写测试程序将D问题。就我个言Q我喜欢在编写少量代码之前或紧接着的之后就~写单元试--q不会打破工作流E,因ؓ它就是流E的一部分?br />     q需要一点儿实践l验--~Zl验的开发者经ؓ要写什么样的测试程序而烦恹{但q可能也反映Z个事实:他们同样也不知道要写什么样的代码。一些h评说TDD能够鼓励q行微设?-一U非常底层的设计Q它不需要考虑较大的场景。这会发生在~Zl验的开发者n上;如果你教条般地应用这U方法,同样也会遇上。像行ؓ驱动开发这LҎ在此处就会很酗当你在写getterҎ之前Q你会写一个针对这个getterҎ的单元测试吗Q如果是的话Q那么你的单元测试专注的层次p高了Q也会更接近于用?或系l?的需求?br />     回到问题的本质,Z么我喜欢把单元测试放在最开始的位置Q很单!我的实践l验告诉我,那样可以帮助提高代码的质量,q且节约调试旉。在开始时写十个小的单元测试所q旉比在以后修复Bug所q旉要少Q如果代码经q了正确的单元测试,那就不会有Bug了?br />     事实上,我屡屡见刎ͼ如果某些代码l过了适当的单元测试,那么׃会有~码问题。最q就有一个例子:׃一个小时的旉L寻Web应用中的一个问题,该问题出现在一个编写正的Spring-MVCE序中。结果是׃一个检验器cd略了一个异常。很Ҏ发Cq个问题Q实际上Q在看了代码(代码?Code Review)也很有效)之后立刻发C。但关键是,我们׃一个小时甚x多的旉Lq个需要进行检查的cR如果这些代码经q了适当的测试,那么p很快地发现ƈ解决q个问题?br />     Ҏ我的l验Q当Z在编写完E序之后才开始编写单元测试,如同事后才有这LxQ他们很隑ֆ些测试了 ("我已l完成了所有的代码Q此时我q得d单元试")。或者根本就不去做。在q种情况下,代码是否完成了呢Q如果代码运行地很好Q那q是完成了。这L话,再写单元试大大地丧失了它的h倹{还不仅如此Q事后编写的单元试是肤浅的,不会对代码进行良好地试。或者,开发者已l耗完了时_他们Ҏ׃惛_为单元测试伤了?br />     TDD与Q何其它的~码实践一栗当你正在学习某个新的技术时Q你会們֐于对学习指导亦步亦趋。类似地Q当你学习一Ҏ术时Q你也会试着一步步地模仿大师的动作Q而不必去理解其中的逻辑。一旦你熟悉了某个技术,能够熟练C用它Qƈ对它有了更深入地理解Q?em>然后Q你p改进它,q与你之前掌握的其它技术进行溶合了?br />
译注
[1]John?a >Java Power Tools一书的M者,也是java.net中一位活跃的Blogger?br />
译后
    上周在java.net上看到这BlogQ再联想到自己在qx工作中的单元试实践Q有些感触,故将其翻译了出来Q与大家׃n?br />     事先q写单元测试,q是事后才编写单元测试?q是一个老问题。按照TDD的思想Q自然是要先~写单元试Q然后再~写能够通过该单元测试的Ҏ?br />     但,单元试q不是TDD的专属领圎ͼ很多不实践TDD的项目也在应用着单元试?br />     我认为,在不实践TDD的项目中(我自己所处的环境是如此)Q事后编写单元测试仍有着其合理性:
    1. 以消极的态度来看Q既焉目本w不严格要求事先~写单元试Q那么就可以在事后去做了。这臛_比不d要好Q聊胜于无嘛?嘿嘿Q是够消极的Q但也拿你没办法)
    2. 事后~写单元试臛_也是一U检验手D,当然Q肯定比不上事先~写的单元测试。因为,事后~写的单元测试很可能?就"已经写好的应用程序,正如John所?事后~写的单元测试将是肤的Q不会对代码q行良好地测?。但...仍然是聊胜于无嘛 :-D (哈哈Q有完没完了)
    3. 可以把单元测试,其中包含事后单元测试,作ؓ"后来?了解、学习应用程序的手段。因为单元测试程序就是应用程序的"客户"Q所以无论它是事先写的,q是事后写的Q都能够表现出应用程序的行ؓ?br />     4. 事后单元试Q也可能转化Z先单元测试。在应用E序的整个生命周期中Q维护阶D|最长的。在"漫长"的维护过E中Q?之前"所写的"事后"单元试会成ؓ"后来?(包括原始作者本??事先"单元试。在改进E序的过E中Q这些单元测试仍然能起到监督的作用?orzQ有点儿诡辩)
    虽然Q事后单元测试明显不如事先单元测试,但它的作用仍然不可低估。只要编写了优秀的单元测试程序,无论是在哪个阶段Q它都会Ҏq应用程序有莫大的帮助?q可不是"聊胜于无"能够表达?



Sha Jiang 2008-06-09 20:55 发表评论
]]>
վ֩ģ壺 | ƽ| ½| ַ| ɽ| | Դ| Ϫ| | Ѩ| ɽ| ԭ| ɳ| | ˮ| ͼʲ| | | Զ| | | ΢| Ԫ| Ϊ| | | | | ʯ| | ɽ| Դ| | ԫ| ̶| | | ʲ| ׯ| | |