如何实现Java测试的自定义断言
作者:网络转载 发布时间:[ 2014/7/3 14:52:55 ] 推荐标签:Java测试
现在我们看看RangeAssert类的其余内容。hasRange()和isSortedAscending()方法(显示在下一个代码列表中)是自定义断言方法的典型例子。它们具有以下共同点:
它们都先调用isNotNull()方法,检查被测对象是否为null。确保这个校验不会失败并抛出NullPointerException异常消息。(这一步不是必须的,但建议有这一步)
它们都返回“this”(也是自定义断言类的对象,对应例子中RangeAssert类的对象)。这使得所有方法可以串在一起。
它们都使用AssertJ Assertions类(属于AssertJ框架)提供的断言方法执行校验。
它们都使用“真实”的对象(由父类ListAssert提供),确保Range列表(List<Range>)被校验。
|
private final static SimpleDateFormat SDF
= new SimpleDateFormat("yyyy-MM-dd HH:mm");
public RangeAssert isSortedAscending() {
isNotNull();
long start = 0;
for (int i = 0; i < actual.size(); i++) {
Assertions.assertThat(start)
.isLessThan(actual.get(i).getStart());
start = actual.get(i).getStart();
}
return this;
}
public RangeAssert hasRange(String from, String to) throws ParseException {
isNotNull();
Long dateFrom = SDF.parse(from).getTime();
Long dateTo = SDF.parse(to).getTime();
boolean found = false;
for (Range range : actual) {
if (range.getStart() == dateFrom && range.getEnd() == dateTo) {
found = true;
}
}
Assertions
.assertThat(found)
.isTrue();
return this;
}
}
|
那么错误信息呢?AssertJ让我们可以很容易地添加错误信息。对于简单的场景,例如值的比较,通常使用as()方法足够了,示例如下:
Assertions
.assertThat(actual.size())
.as("number of ranges")
.isEqualTo(expectedSize);
正如你所见到的,as()只是AssertJ框架提供的另一个方法。当测试失败时,它打印下面的信息,我们立即能知道哪儿错了:
org.junit.ComparisonFailure: [number of ranges]
Expected :4
Actual :3
有时候只知道被测对象的名字是不够的,我们需要更多信息以了解到底发生了什么。以hasRange()方法为例,当测试失败时,如果能够打印所有range更好了。我们可以通过overridingErrorMessage()方法来实现这种效果:
public RangeAssert hasRange(String from, String to) throws ParseException {
...
String errMsg = String.format("ranges %s do not contain %s-%s",
actual ,from, to);
...
Assertions.assertThat(found)
.overridingErrorMessage(errMsg)
.isTrue();
...
}
现在,当测试失败时,我们能够得到非常详细的信息。它的内容取决于Range类的toString()方法。例如,它看起来可能是这样的:
HourlyRange{Mon Jul 23 12:00:00 CEST 2012 to Mon Jul 23 13:00:00 CEST 2012},
HourlyRange{Mon Jul 23 13:00:00 CEST 2012 to Mon Jul 23 14:00:00 CEST 2012},
HourlyRange{Mon Jul 23 14:00:00 CEST 2012 to Mon Jul 23 15:00:00 CEST 2012}]
do not contain 2012-07-23 16:00-2012-07-23 14:00
总结
在本文中,我们讨论了很多编写断言的方法。我们从“传统”的方式开始,也是基于测试框架提供的断言方法。对于很多场景,这已经非常好了。但是正如我们所看到的,它在表达测试意图时,有时候缺少了一些灵活性。之后,我们通过引入私有断言方法,取得了一点改善,但仍然不是理想的解决方案。后,我们尝试使用AssertJ编写自定义断言,我们的测试代码取得了非常好的可读性和可维护性。
如果要我提供一些关于断言的建议,我将会建议以下内容:如果你停止使用测试框架(例如JUnit或TestNG)提供的断言,改为使用匹配器类库(例如AssertJ或者Hamcrest),你的测试代码将得到极大的改善。你将可以使用大量可读性很强的断言,减少测试代码中//then之后的复杂声明。
尽管编写自定义断言的成本非常低,但也没有必要因为你会写一定要使用它们。当你的测试代码的可读性并且/或者可维护性变差时使用它们。根据我的经验,我会鼓励你在以下场景中使用自定义断言:
当你发现使用匹配器类库提供的断言无法清晰表达测试意图时;
作为私有断言方法的替代方案。
我的经验告诉我,单元测试几乎不需要自定义断言。而在集成测试和端到端测试(功能测试)中,我敢说你肯定会发现它们是不可替代的。它们能让你的测试用领域语言说话(而不是实现语言),它们还封装了技术细节,使测试更易于更新。
关于作者
Tomek Kaczanowski是CodeWise公司(克拉科夫,波兰)的一名Java开发人员。他专注于代码质量、测试和自动化。他是TDD的狂热者、开源的倡导者和敏捷的崇拜者。具有强烈的分享知识倾向。书的作者、博客和会议发言人。Twitter: @tkaczanowski
Assertions
.assertThat(actual.size())
.as("number of ranges")
.isEqualTo(expectedSize);
正如你所见到的,as()只是AssertJ框架提供的另一个方法。当测试失败时,它打印下面的信息,我们立即能知道哪儿错了:
org.junit.ComparisonFailure: [number of ranges]
Expected :4
Actual :3
有时候只知道被测对象的名字是不够的,我们需要更多信息以了解到底发生了什么。以hasRange()方法为例,当测试失败时,如果能够打印所有range更好了。我们可以通过overridingErrorMessage()方法来实现这种效果:
public RangeAssert hasRange(String from, String to) throws ParseException {
...
String errMsg = String.format("ranges %s do not contain %s-%s",
actual ,from, to);
...
Assertions.assertThat(found)
.overridingErrorMessage(errMsg)
.isTrue();
...
}
现在,当测试失败时,我们能够得到非常详细的信息。它的内容取决于Range类的toString()方法。例如,它看起来可能是这样的:
HourlyRange{Mon Jul 23 12:00:00 CEST 2012 to Mon Jul 23 13:00:00 CEST 2012},
HourlyRange{Mon Jul 23 13:00:00 CEST 2012 to Mon Jul 23 14:00:00 CEST 2012},
HourlyRange{Mon Jul 23 14:00:00 CEST 2012 to Mon Jul 23 15:00:00 CEST 2012}]
do not contain 2012-07-23 16:00-2012-07-23 14:00
总结
在本文中,我们讨论了很多编写断言的方法。我们从“传统”的方式开始,也是基于测试框架提供的断言方法。对于很多场景,这已经非常好了。但是正如我们所看到的,它在表达测试意图时,有时候缺少了一些灵活性。之后,我们通过引入私有断言方法,取得了一点改善,但仍然不是理想的解决方案。后,我们尝试使用AssertJ编写自定义断言,我们的测试代码取得了非常好的可读性和可维护性。
如果要我提供一些关于断言的建议,我将会建议以下内容:如果你停止使用测试框架(例如JUnit或TestNG)提供的断言,改为使用匹配器类库(例如AssertJ或者Hamcrest),你的测试代码将得到极大的改善。你将可以使用大量可读性很强的断言,减少测试代码中//then之后的复杂声明。
尽管编写自定义断言的成本非常低,但也没有必要因为你会写一定要使用它们。当你的测试代码的可读性并且/或者可维护性变差时使用它们。根据我的经验,我会鼓励你在以下场景中使用自定义断言:
当你发现使用匹配器类库提供的断言无法清晰表达测试意图时;
作为私有断言方法的替代方案。
我的经验告诉我,单元测试几乎不需要自定义断言。而在集成测试和端到端测试(功能测试)中,我敢说你肯定会发现它们是不可替代的。它们能让你的测试用领域语言说话(而不是实现语言),它们还封装了技术细节,使测试更易于更新。
关于作者
Tomek Kaczanowski是CodeWise公司(克拉科夫,波兰)的一名Java开发人员。他专注于代码质量、测试和自动化。他是TDD的狂热者、开源的倡导者和敏捷的崇拜者。具有强烈的分享知识倾向。书的作者、博客和会议发言人。Twitter: @tkaczanowski
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Java性能测试有哪些不为众人所知的原则?Java设计模式??装饰者模式谈谈Java中遍历Map的几种方法Java Web入门必知你需要理解的Java反射机制知识总结编写更好的Java单元测试的7个技巧编程常用的几种时间戳转换(java .net 数据库)适合Java开发者学习的Python入门教程Java webdriver如何获取浏览器新窗口中的元素?Java重写与重载(区别与用途)Java变量的分类与初始化JavaScript有这几种测试分类Java有哪四个核心技术?给 Java开发者的10个大数据工具和框架Java中几个常用设计模式汇总java生态圈常用技术框架、开源中间件,系统架构及经典案例等

sales@spasvo.com