`

探索JUnit4扩展:断言语法assertThat

阅读更多

一.概述

        JUnit 设计的目的就是有效地抓住编程人员写代码的意图,然后快速检查他们的代码是否与他们的意图相匹配。 JUnit 发展至今,版本不停的翻新,但是所有版本都一致致力于解决一个问题,那就是如何发现编程人员的代码意图,并且如何使得编程人员更加容易地表达他们的代码意图。JUnit 4.4 也是为了如何能够更好的达到这个目的而出现的。

        JUnit 4.4 主要提供了以下三个大方面的新特性来更好的抓住编程人员的代码意图:

a.提供了新的断言语法(Assertion syntax)——assertThat
b.提供了假设机制(Assumption)
c.提供了理论机制(Theory)——上篇已介绍

 

二.assertThat

        下面具体来探索下新的断言语法(Assertion syntax)——assertThat
        JUnit 4.4 学习JMock,引入了 Hamcrest 匹配机制,使得程序员在编写单元测试的 assert 语句时,可以具有更强的可读性,而且也更加灵活。

        Hamcrest 是一个测试的框架,它提供了一套通用的匹配符 Matcher,灵活使用这些匹配符定义的规则,程序员可以更加精确的表达自己的测试思想,指定所想设定的测试条件。比如,有时候定义的测试数据范围太精确,往往是若干个固定的确定值,这时会导致测试非常脆弱,因为接下来的测试数据只要稍稍有变化,就可能导致测试失败(比如 assertEquals( x, 10 ); 只能判断 x 是否等于10,如果x不等于10,测试失败);有时候指定的测试数据范围又不够太精确,这时有可能会造成某些本该会导致测试不通过的数据,仍然会通过接下来的测试,这样就会降低测试的价值。Hamcrest 的出现,给程序员编写测试用例提供了一套规则和方法,使用其可以更加精确的表达程序员所期望的测试的行为。

        JUnit 4.4 结合 Hamcrest 提供了一个全新的断言语法——assertThat。程序员可以只使用 assertThat 一个断言语句,结合 Hamcrest 提供的匹配符,就可以表达全部的测试思想。

1.assertThat 的基本语法如下:

assertThat( [value], [matcher statement] );

        value 是接下来想要测试的变量值;

        matcher statement 是使用Hamcrest 匹配符来表达的对前面变量所期望的值的声明,如果 value 值与 matcher statement 所表达的期望值相符,则测试成功,否则测试失败。

2.assertThat 的优点

        优点1:以前 JUnit 提供了很多的 assertion 语句,如:assertEquals,assertNotSame,assertFalse,assertTrue,assertNotNull,assertNull 等,现在有了 JUnit 4.4,一条 assertThat 即可以替代所有的 assertion 语句,这样可以在所有的单元测试中只使用一个断言方法,使得编写测试用例变得简单,代码风格变得统一,测试代码也更容易维护。

        优点2:assertThat 使用了Hamcrest 的Matcher 匹配符,用户可以使用匹配符规定的匹配准则精确的指定一些想设定满足的条件,具有很强的易读性,而且使用起来更加灵活。如下所示使用匹配符 Matcher 和不使用之间的比较:

// 想判断某个字符串 s 是否含有子字符串 "developer" 或 "Works" 中间的一个
// JUnit 4.4 以前的版本:assertTrue(s.indexOf("developer")>-1||s.indexOf("Works")>-1 );
// JUnit 4.4:
assertThat(s, anyOf(containsString("developer"), containsString("Works"))); 
// 匹配符 anyOf 表示任何一个条件满足则成立,类似于逻辑或 "||", 匹配符 containsString 表示是否含有参数子 
// 字符串,文章接下来会对匹配符进行具体介绍 

        优点3:assertThat 不再像 assertEquals 那样,使用比较难懂的“谓宾主”语法模式(如:assertEquals(3, x);),相反,assertThat 使用了类似于“主谓宾”的易读语法模式(如:assertThat(x,is(3));),使得代码更加直观、易读。

        优点4:可以将这些 Matcher 匹配符联合起来灵活使用,达到更多目的。如下所示Matcher 匹配符联合使用:

// 联合匹配符not和equalTo表示“不等于”
assertThat( something, not( equalTo( "developer" ) ) ); 
// 联合匹配符not和containsString表示“不包含子字符串”
assertThat( something, not( containsString( "Works" ) ) ); 
// 联合匹配符anyOf和containsString表示“包含任何一个子字符串”
assertThat(something, anyOf(containsString("developer"), containsString("Works")));

        优点5:错误信息更加易懂、可读且具有描述性(descriptive)
        JUnit 4.4 以前的版本默认出错后不会抛出额外提示信息,如:

assertTrue( s.indexOf("developer") > -1 || s.indexOf("Works") > -1 );

        如果该断言出错,只会抛出无用的错误信息,如:junit.framework.AssertionFailedError:null。

        如果想在出错时想打印出一些有用的提示信息,必须得程序员另外手动写,如:

assertTrue( "Expected a string containing 'developer' or 'Works'",  s.indexOf("developer") > -1 || s.indexOf("Works") > -1 );

        非常的不方便,而且需要额外代码。

        JUnit 4.4 会默认自动提供一些可读的描述信息,如下所示JUnit 4.4 默认提供一些可读的描述性错误信息:

String s = "hello world!"; 
assertThat( s, anyOf( containsString("developer"), containsString("Works") ) ); 
// 如果出错后,系统会自动抛出以下提示信息:
java.lang.AssertionError: 
Expected: (a string containing "developer" or a string containing "Works") 
got: "hello world!"

        优点6:开发人员可以通过实现 Matcher 接口,定制自己想要的匹配符。当开发人员发现自己的某些测试代码在不同的测试中重复出现,经常被使用,这时用户就可以自定义匹配符,将这些代码绑定在一个断言语句中,从而可以达到减少重复代码并且更加易读的目的。(具体怎么实现自定义可配置的匹配符,请参阅相关资料)

3.如何使用assertThat
        JUnit 4.4 自带了一些 Hamcrest 的匹配符Matcher,但是只有有限的几个,在类org.hamcrest.CoreMatchers 中定义,要想使用他们,必须导入包 org.hamcrest.CoreMatchers.*。

        如果想使用一些其他更多的匹配符 Matcher,可以从 Hamcrest 网页下载 hamcrest-library-1.1.jar 和 hamcrest-core-1.1.jar(请参阅 参考资料),并将其加入到工程库中,所有的匹配符都在类 org.hamcrest.Matchers 中定义,要想使用,必须得在代码中import static org.hamcrest.Matchers.*;。如果使用外部的匹配符,最好就不要再使用 JUnit 4.4 自带的匹配符了,因为这样容易导致匹配符Matcher 重复定义,编译可能会出错(ambiguous for the type)。JUnit 4.4 允许使用 Hamcrest 来使用更多的匹配符,这还是 JUnit 第一次允许在自己的工程中使用第三方类。

注意:

        1.assertThat 仍然是断言语句,所以要想使用,必须还得 import static org.junit.Assert.*;;
        2.虽然 assertThat 可以代替以前所有的断言语句,但是以前的所有 assert 语句仍然可以继续使用;
下面列举了大部分assertThat 的使用例子:

//一般匹配符

// allOf匹配符表明如果接下来的所有条件必须都成立测试才通过,相当于“与”(&&)
assertThat( testedNumber, allOf( greaterThan(8), lessThan(16) ) );
// anyOf匹配符表明如果接下来的所有条件只要有一个成立则测试通过,相当于“或”(||)
assertThat( testedNumber, anyOf( greaterThan(16), lessThan(8) ) );
// anything匹配符表明无论什么条件,永远为true
assertThat( testedNumber, anything() );
// is匹配符表明如果前面待测的object等于后面给出的object,则测试通过
assertThat( testedString, is( "developerWorks" ) );
// not匹配符和is匹配符正好相反,表明如果前面待测的object不等于后面给出的object,则测试通过
assertThat( testedString, not( "developerWorks" ) );

//字符串相关匹配符

// containsString匹配符表明如果测试的字符串testedString包含子字符串"developerWorks"则测试通过
assertThat( testedString, containsString( "developerWorks" ) );
// endsWith匹配符表明如果测试的字符串testedString以子字符串"developerWorks"结尾则测试通过
assertThat( testedString, endsWith( "developerWorks" ) ); 
// startsWith匹配符表明如果测试的字符串testedString以子字符串"developerWorks"开始则测试通过
assertThat( testedString, startsWith( "developerWorks" ) ); 
// equalTo匹配符表明如果测试的testedValue等于expectedValue则测试通过,equalTo可以测试数值之间,字
//符串之间和对象之间是否相等,相当于Object的equals方法
assertThat( testedValue, equalTo( expectedValue ) ); 
// equalToIgnoringCase匹配符表明如果测试的字符串testedString在忽略大小写的情况下等于
//"developerWorks"则测试通过
assertThat( testedString, equalToIgnoringCase( "developerWorks" ) ); 
// equalToIgnoringWhiteSpace匹配符表明如果测试的字符串testedString在忽略头尾的任意个空格的情况下等
//于"developerWorks"则测试通过,注意:字符串中的空格不能被忽略
assertThat( testedString, equalToIgnoringWhiteSpace( "developerWorks" ) );

//数值相关匹配符

// closeTo匹配符表明如果所测试的浮点型数testedDouble在20.0±0.5范围之内则测试通过
assertThat( testedDouble, closeTo( 20.0, 0.5 ) );
// greaterThan匹配符表明如果所测试的数值testedNumber大于16.0则测试通过
assertThat( testedNumber, greaterThan(16.0) );
// lessThan匹配符表明如果所测试的数值testedNumber小于16.0则测试通过
assertThat( testedNumber, lessThan (16.0) );
// greaterThanOrEqualTo匹配符表明如果所测试的数值testedNumber大于等于16.0则测试通过
assertThat( testedNumber, greaterThanOrEqualTo (16.0) );
// lessThanOrEqualTo匹配符表明如果所测试的数值testedNumber小于等于16.0则测试通过
assertThat( testedNumber, lessThanOrEqualTo (16.0) );

//collection相关匹配符

// hasEntry匹配符表明如果测试的Map对象mapObject含有一个键值为"key"对应元素值为"value"的Entry项则
//测试通过
assertThat( mapObject, hasEntry( "key", "value" ) );
// hasItem匹配符表明如果测试的迭代对象iterableObject含有元素“element”项则测试通过
assertThat( iterableObject, hasItem ( "element" ) );
// hasKey匹配符表明如果测试的Map对象mapObject含有键值“key”则测试通过
assertThat( mapObject, hasKey("key"));
// hasValue匹配符表明如果测试的Map对象mapObject含有元素值“value”则测试通过
assertThat( mapObject, hasValue("key"));

 

文章来源:http://www.ibm.com/developerworks/cn/java/j-lo-junit44/
分享到:
评论

相关推荐

    探索JUnit4扩展:深入Rule

    《探索JUnit4扩展:深入Rule》 JUnit是Java开发者最常用的单元测试框架,它极大地简化了测试代码的编写。在JUnit4中,引入了一个强大的特性——Rule,这使得测试更加灵活且可定制化。本文将深入探讨Rule的概念、...

    探索JUnit4扩展:使用Rule

    标题“探索JUnit4扩展:使用Rule”涉及到的是Java单元测试框架JUnit的一个高级特性,即`@Rule`。在Java开发中,单元测试是确保代码质量、可维护性和可靠性的重要手段,而JUnit作为最流行的Java单元测试框架之一,...

    Junit4.12和依赖包

    其次,Junit4.12提供了断言(Assertion)机制,用于检查代码的运行结果是否符合预期。例如,`assertEquals()`用于比较两个值是否相等,`assertTrue()`和`assertFalse()`用来验证布尔条件。此外,还有`assertNull()`...

    junit-libs:junit测试包

    - 扩展性:JUnit Jupiter提供了一种可扩展的测试架构,开发者可以自定义测试注解和执行逻辑。 - Vintage模块:为兼容JUnit 4的测试用例,JUnit 5包含了Vintage模块。 3. 使用JUnit进行测试: - 引入依赖:在项目...

    junit-jupiter-api-5.4.2-API文档-中英对照版.zip

    赠送jar包:junit-jupiter-api-5.4.2.jar; 赠送原API文档:junit-jupiter-api-5.4.2-javadoc.jar; 赠送源代码:junit-jupiter-api-5.4.2-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-api-5.4.2.pom; ...

    junit-4.12.rar包及依赖包

    本文将深入探讨关于"junit-4.12.rar"包及其依赖包,以及如何解决在使用JUnit 4进行单元测试时遇到的"method initializationerror not found"错误。 首先,我们来了解JUnit 4.12版本。这是JUnit的一个稳定版本,发布...

    JUnit4基础文档

    本文档介绍了JUnit4的基础知识,包括单元测试的概念、JUnit4的HelloWorld示例、断言机制、注解使用、测试运行方式等。 单元测试的概念 单元测试是指对软件的最小单元进行测试,以确保其正确性和可靠性。单元测试...

    使用Junit4.12需要用的两个包,官网在国内无法下载

    首先,JUnit 4.12是JUnit系列的一个版本,发布于2013年,提供了丰富的断言方法、测试注解和参数化测试等功能,极大地简化了单元测试的编写。在使用JUnit 4.12时,通常需要两个核心的jar包:junit.jar和hamcrest-core...

    junit-4.13.1.jar

    JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。

    junit-platform-launcher-1.8.0-M1-API文档-中文版.zip

    赠送jar包:junit-platform-launcher-1.8.0-M1.jar; 赠送原API文档:junit-platform-launcher-1.8.0-M1-javadoc.jar; 赠送源代码:junit-platform-launcher-1.8.0-M1-sources.jar; 赠送Maven依赖信息文件:junit-...

    junit-jupiter-engine-5.8.2-API文档-中文版.zip

    赠送jar包:junit-jupiter-engine-5.8.2.jar; 赠送原API文档:junit-jupiter-engine-5.8.2-javadoc.jar; 赠送源代码:junit-jupiter-engine-5.8.2-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-engine-...

    junit-jupiter-api-5.8.0-M1-API文档-中英对照版.zip

    赠送jar包:junit-jupiter-api-5.8.0-M1.jar; 赠送原API文档:junit-jupiter-api-5.8.0-M1-javadoc.jar; 赠送源代码:junit-jupiter-api-5.8.0-M1-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-api-5.8.0-...

    junit单元测试

    JUnit Vintage则是为了兼容JUnit 4而存在的。 使用JUnit 5,开发者可以编写更加灵活和可读的测试代码,例如通过参数化测试来运行同一测试用例的不同数据组合,或者使用条件注解来控制测试执行的条件。另外,JUnit 5...

    junit-4.11.jar

    4. **可扩展性**:JUnit 4.11允许用户自定义规则(Rules),通过@Rule注解,可以创建复杂的测试行为,如临时文件管理、超时控制等。 5. **分类(Categories)**:新增了测试分类功能,开发者可以将测试分为不同的...

    junit-4.11 jar包、源文件、操作文档

    为了在项目中使用JUnit,你需要将`junit-4.11.jar`添加到项目的类路径中,并在测试类上使用`@RunWith(JUnit4.class)`注解来指定使用JUnit 4作为测试运行器。然后,你可以创建测试方法,这些方法通常以`test`开头,并...

    junit-jupiter-api-5.8.2-API文档-中文版.zip

    赠送jar包:junit-jupiter-api-5.8.2.jar; 赠送原API文档:junit-jupiter-api-5.8.2-javadoc.jar; 赠送源代码:junit-jupiter-api-5.8.2-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-api-5.8.2.pom; ...

    junit-vintage-engine-5.6.2.jar_junit testng

    junit-vintage-engine-5.6.2.jarjunit-vintage-engine-5.6.2.jarjunit-vintage-engine-5.6.2.jar

    Junit4使用方法

    JUnit4 提供了多种断言方法,例如: * assertArrayEquals:断言两个数组相等 * assertEquals:断言两个对象相等 * assertSame:断言两个对象相同 * assertTrue:断言条件为真 * assertNotNull:断言对象不为 null ...

    junit4教程(《Junit4初探》)

    与JUnit3相比,JUnit4的灵活性和可扩展性得到了显著提升,使得测试驱动开发(TDD)在Java领域变得更加普及。 ## 二、JUnit4的核心组件 ### 1. 测试注解 - `@Test`: 表示一个方法是测试方法,可以包含断言。 - `@...

    初试android studio 创建project时报错:Could not download junit.jar(junit:junit:4.12)

    本人小白,开始学习Android,记录自己的错误瞬间,大神不要喷我,哈哈! 安装好android studio后,测试...如果不在意的话,可以不下载它,在module的build.gradle中dependencies模块把加载junit的testCompile ‘junit:j

Global site tag (gtag.js) - Google Analytics