受GeeCON会议期间@tkaczanowski演讲的启发,我决定仔细研究AssertJ库的自定义断言。

在我的“骰子”游戏中,我创建了一个“机会”,它是骰子的任意组合,其分数是所有骰子的总和。 这是相对简单的对象:

class Chance implements Scorable {@Overridepublic Score getScore(Collection<Dice> dice) {int sum = dice.stream().mapToInt(die -> die.getValue()).sum();return scoreBuilder(this).withValue(sum).withCombination(dice).build();}
}public interface Scorable {Score getScore(Collection<Dice> dice);
}

在我的测试中,我想看看如何计算不同骰子组合的分数。 我从简单开始(实际上只有一个):

public class ChanceTest {private Chance chance = new Chance();@Test@Parameterspublic void chance(Collection<Dice> rolled, int scoreValue) {// arrangeCollection<Dice> rolled = dice(1, 1, 3, 3, 3);// actScore score = chance.getScore(rolled);// assertassertThat(actualScore.getScorable()).isNotNull();assertThat(actualScore.getValue()).isEqualTo(expectedScoreValue);assertThat(actualScore.getReminder()).isEmpty();assertThat(actualScore.getCombination()).isEqualTo(rolled);}}

测试中验证了单个概念(得分对象)。 为了提高分数验证的可读性和可重用性,我将创建一个自定义断言。 我希望我的断言像其他任何AssertJ断言一样被使用,如下所示:

public class ChanceTest {private Chance chance = new Chance();@Testpublic void scoreIsSumOfAllDice() {Collection<Dice> rolled = dice(1, 1, 3, 3, 3);Score score = chance.getScore(rolled);ScoreAssertion.assertThat(score).hasValue(11).hasNoReminder().hasCombination(rolled);}
}

为了实现这一点,我需要创建一个从org.assertj.core.api.AbstractAssert扩展的ScoreAssertion类。 该类应具有公共的静态工厂方法和所有必需的验证方法。 最后,实现可能如下图所示。

class ScoreAssertion extends AbstractAssert<ScoreAssertion, Score> {protected ScoreAssertion(Score actual) {super(actual, ScoreAssertion.class);}public static ScoreAssertion assertThat(Score actual) {return new ScoreAssertion(actual);}public ScoreAssertion hasEmptyReminder() {isNotNull();if (!actual.getReminder().isEmpty()) {failWithMessage("Reminder is not empty");}return this;}public ScoreAssertion hasValue(int scoreValue) {isNotNull();if (actual.getValue() != scoreValue) {failWithMessage("Expected score to be <%s>, but was <%s>", scoreValue, actual.getValue());}return this;}public ScoreAssertion hasCombination(Collection<Dice> expected) {Assertions.assertThat(actual.getCombination()).containsExactly(expected.toArray(new Dice[0]));return this;}
}

创建这样的断言的动机是拥有更多可读性和可重用性的代码。 但是它要付出一些代价–需要创建更多代码。 在我的示例中,我知道我很快就会创建更多的Scorables并且需要验证它们的评分算法,因此创建额外的代码是合理的。 增益将可见。 例如,我创建了一个NumberInARow类,该类计算给定骰子组合中所有连续数字的分数。 分数是具有给定值的所有骰子的总和:

class NumberInARow implements Scorable {private final int number;public NumberInARow(int number) {this.number = number;}@Overridepublic Score getScore(Collection<Dice> dice) {Collection<Dice> combination = dice.stream().filter(value -> value.getValue() == number).collect(Collectors.toList());int scoreValue = combination.stream().mapToInt(value -> value.getValue()).sum();Collection<Dice> reminder = dice.stream().filter(value -> value.getValue() != number).collect(Collectors.toList());return Score.scoreBuilder(this).withValue(scoreValue).withReminder(reminder).withCombination(combination).build();}
}

我从连续检查两个5的测试开始,但是我已经错过了断言( hasReminder ,因此改进了ScoreAssertion 。 我继续通过其他测试更改断言,直到获得可以在测试中使用的非常完善的DSL:

public class NumberInARowTest {@Testpublic void twoFivesInARow() {NumberInARow numberInARow = new NumberInARow(5);Collection<Dice> dice = dice(1, 2, 3, 4, 5, 5);Score score = numberInARow.getScore(dice);// static import ScoreAssertionassertThat(score).hasValue(10).hasCombination(dice(5, 5)).hasReminder(dice(1, 2, 3, 4));}@Testpublic void noNumbersInARow() {NumberInARow numberInARow = new NumberInARow(5);Collection<Dice> dice = dice(1, 2, 3);Score score = numberInARow.getScore(dice);assertThat(score).isZero().hasReminder(dice(1, 2, 3));}
}public class TwoPairsTest {@Testpublic void twoDistinctPairs() {TwoPairs twoPairs = new TwoPairs();Collection<Dice> dice = dice(2, 2, 3, 3, 1, 4);Score score = twoPairs.getScore(dice);assertThat(score).hasValue(10).hasCombination(dice(2, 2, 3, 3)).hasReminder(dice(1, 4));}
}

更改后的断言如下所示:

class ScoreAssertion extends AbstractAssert<ScoreAssertion, Score> {protected ScoreAssertion(Score actual) {super(actual, ScoreAssertion.class);}public static ScoreAssertion assertThat(Score actual) {return new ScoreAssertion(actual);}public ScoreAssertion isZero() {hasValue(Score.ZERO);hasNoCombination();return this;}public ScoreAssertion hasValue(int scoreValue) {isNotNull();if (actual.getValue() != scoreValue) {failWithMessage("Expected score to be <%s>, but was <%s>",scoreValue, actual.getValue());}return this;}public ScoreAssertion hasNoReminder() {isNotNull();if (!actual.getReminder().isEmpty()) {failWithMessage("Reminder is not empty");}return this;}public ScoreAssertion hasReminder(Collection<Dice> expected) {isNotNull();Assertions.assertThat(actual.getReminder()).containsExactly(expected.toArray(new Dice[0]));return this;}private ScoreAssertion hasNoCombination() {isNotNull();if (!actual.getCombination().isEmpty()) {failWithMessage("Combination is not empty");}return this;}public ScoreAssertion hasCombination(Collection<Dice> expected) {isNotNull();Assertions.assertThat(actual.getCombination()).containsExactly(expected.toArray(new Dice[0]));return this;}
}

我真的很喜欢自定义AssertJ断言的想法。 在某些情况下,它们将提高我的代码的可读性。 另一方面,我很确定不能在所有情况下使用它们。 特别是在那些可重用机会很小的地方。 在这种情况下,可以使用带有分组断言的私有方法。

你有什么意见?

资源资源

  • https://github.com/joel-costigliola/assertj-core/wiki/Creating-specific-assertions
  • @tkaczanowski的断言演变

翻译自: https://www.javacodegeeks.com/2014/05/spice-up-your-test-code-with-custom-assertions.html

使用自定义断言丰富测试代码相关推荐

  1. mock测试使用断言_使用自定义断言丰富测试代码

    mock测试使用断言 受GeeCON会议期间@tkaczanowski演讲的启发,我决定仔细研究AssertJ库的自定义断言. 在我的"骰子"游戏中,我创建了一个"机会& ...

  2. apachejmeter_java源码_自定义编写jmeter的Java测试代码

    我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如LoadRunner就有很多自定义脚本的协议,比如"C Vuser","JavaV ...

  3. jmeter之java代码性能测试_松勤软件性能测试-自定义编写的Java测试代码在Jmeter中如何使用...

    原标题:松勤软件性能测试-自定义编写的Java测试代码在Jmeter中如何使用 我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如LoadRunner就有很多自定 ...

  4. 使用C#为MSTest测试项目实现自定义断言

    前言 MSTest测试项目为我们实现了断言类Assert,用于报告代码行为的正确性,比如: var result = Calculator.Add(1,2); Assert.AreEqual(3, r ...

  5. java断言assertequals_如何实现Java测试的自定义断言

    这些信息太不清晰,理应得到改善. 私有方法 那么,我们究竟能做些什么呢?好吧,最显而易见的办法是将断言抽成一个私有方法: private void assertThatRangeExists(List ...

  6. idea2020shezhi代码检查级别_优秀的模糊测试代码是如何炼成的?

    所谓模糊测试,是指一种通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法,它经过了近 20 年的发展,早已在程序员圈中成为一种主流漏洞挖掘技术.基于此,开发者们该如何编写良好的模糊测试代 ...

  7. 存根类 测试代码 java_测试双打:模拟,假人和存根

    存根类 测试代码 java 大多数班级都有合作者. 在进行单元测试时,您通常希望避免使用那些协作者的实际实现方式来避免测试的脆弱性和绑定/耦合,而应使用测试双打:模拟,存根和双打. 本文引用了有关该主 ...

  8. 隐藏画质代码_优秀的模糊测试代码是如何炼成的?

    所谓模糊测试,是指一种通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法,它经过了近 20 年的发展,早已在程序员圈中成为一种主流漏洞挖掘技术.基于此,开发者们该如何编写良好的模糊测试代 ...

  9. 优秀的模糊测试代码是如何炼成的?

    所谓模糊测试,是指一种通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法,它经过了近 20 年的发展,早已在程序员圈中成为一种主流漏洞挖掘技术.基于此,开发者们该如何编写良好的模糊测试代 ...

最新文章

  1. kenrel volatile关键字
  2. bmob php支付,基于Bmob在小程序端实现一键支付
  3. 学习笔记Hadoop(十五)—— MapReduce编程进阶
  4. 爬虫-scrapy数据的持久化存储
  5. jdk下载--操作系统
  6. DeadXSpace项目进度
  7. Codeforces 490F Treeland Tour(离散化 + 线段树合并)
  8. 简单类型参数是值传递,对象参数是引用传递
  9. 数学和计算机竞赛,数学奥赛VS信息学奥赛,数学基础扎实的孩子
  10. Python实现批量采集美女shipin<无水印>
  11. 三角函数和复指数函数的转化_【导数压轴】当三角函数遇到导数02
  12. 共享磁盘到远程服务器上,远程桌面链接怎么共享本地磁盘,你值得一看的技巧...
  13. 关于MATLAB直方图的绘制及应用
  14. 去除URL中带有的jsessionid
  15. CFA一级学习笔记--固定收益(一)--基本概念
  16. raw data convert and play
  17. 如何给图片标注重点(加红框、箭头等)\一些好用的快捷键
  18. 自考计算机专业的草根,我找到了自己的南方——《草根考研心经》传授
  19. PM面试集:常见问题及解题思路
  20. 【windows10 切换应用程序、虚拟桌面的快捷键, 详细使用教程】

热门文章

  1. System.err: java.net.UnknownServiceException: CLEARTEXT communication to 192.168.43.172 not permitte
  2. 机器人点焊枪接线_用于焊接机器人焊枪工具点及工件坐标系标定装置及方法与流程...
  3. 34.在排序数组中查找元素的第一个和最后一个位置--leetcode算法题解(带注释)
  4. netflix 模式创新_创新设计模式:单例模式
  5. Spring Boot和Apache Camel
  6. vaadin_Vaadin提示:以声明方式构建UI
  7. matchers依赖_定制Hamcrest Matchers
  8. java ee的小程序_Java EE应用程序的单片到微服务重构
  9. 内存泄露严重吗_内存泄漏–测量频率和严重性
  10. sap-erp实施心得_实施动态代理-比较