Одно из правил написания хорошего модульного теста состоит в том, что он должен потерпеть неудачу по одной причине, поэтому модульный тест должен проверить одну логическую концепцию. Иногда довольно сложно иметь одно утверждение на тест. Чтобы следовать правилу, мы можем иметь несколько утверждений на объект в одном тесте.
Однако проблема с несколькими утверждениями в одном тесте заключается в том, что если первое по какой-либо причине не удается, мы фактически не знаем о других утверждениях, поскольку они не будут выполнены. И вы знаете упражнение: вы проверяете причину ошибки утверждения, исправляете ее и повторно запускаете тест. Может быть, вам повезет, и испытание пройдет. Но, может быть, это не удастся с другим утверждением. С очень быстрыми юнит-тестами это не является большой проблемой, но когда дело касается, например, анализа тестов Selenium и обнаружения сбоев, они могут стать громоздкими и требующими много времени.
 К счастью, мы можем переосмыслить способ создания утверждений в наших тестах благодаря SoftAssertions SoftAssertions . 
Одно утверждение, чтобы управлять ими всеми!
  В гипотетической игре в Dice есть объект Score который содержит значение счета, комбинацию игральных костей и напоминание.  В модульных тестах мы можем захотеть проверить, как рассчитывается оценка для другой комбинации костей. 
В приведенном ниже примере проверяется одна концепция — объект оценки:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
 | 
@Testpublic void verifiesScore() {    Score score = Score.scoreBuilder()                       .withValue(11)                       .withCombination(dice(1, 1, 3, 4))                       .withReminder(dice(6))                       .build();    assertThat(score.getValue())        .as("Has score")        .isEqualTo(8);    assertThat(score.getCombination())        .as("Has combination")        .isEqualTo(dice(1, 1, 3, 3));    assertThat(score.getReminder())        .as("Has reminder")        .isEqualTo(dice(5));} | 
Как видите, все три утверждения терпят неудачу, но мы увидим только результат первого сбоя, поскольку выполнение теста прекращается после первого сбоя:
| 
 1 
2 
3 
 | 
org.junit.ComparisonFailure: [Has score] Expected :8Actual   :11 | 
  Представляем SoftAssertions 
  Чтобы исправить это, мы можем использовать SoftAssertions которые будут собирать результат всех утверждений сразу после вызова assertAll() : 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
 | 
@Testpublic void verifiesScoreSoftly() {    Score score = Score.scoreBuilder()                       .withValue(11)                       .withCombination(dice(1, 1, 3, 4))                       .withReminder(dice(6))                       .build();    SoftAssertions softAssertions = new SoftAssertions();    softAssertions.assertThat(score.getValue())                  .as("Has score")                  .isEqualTo(8);    softAssertions.assertThat(score.getCombination())                  .as("Has combination")                  .isEqualTo(dice(1, 1, 3, 3));    softAssertions.assertThat(score.getReminder())                  .as("Has reminder")                  .isEqualTo(dice(5));    softAssertions.assertAll();} | 
Теперь мы можем проверить все ошибки утверждений в тесте:
| 
 1 
2 
3 
4 
5 
 | 
org.assertj.core.api.SoftAssertionError: The following 3 assertions failed:1) [Has score] expected:<[8]> but was:<[11]>2) [Has combination] expected:<...alue=3}, Dice{value=[3]}]> but was:<...alue=3}, Dice{value=[4]}]>3) [Has reminder] expected:<[Dice{value=[5]}]> but was:<[Dice{value=[6]}]> | 
  JUnitSoftAssertions @Rule 
  Вместо того, чтобы вручную создавать SoftAssertions и вызывать его assertAll() мы можем использовать JUnit @Rule : 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
 | 
@Rulepublic JUnitSoftAssertions softAssertions = new JUnitSoftAssertions();@Testpublic void verifiesScoreSoftlyUsingRule() {    Score score = Score.scoreBuilder()                       .withValue(11)                       .withCombination(dice(1, 1, 3, 4))                       .withReminder(dice(6))                       .build();    softAssertions.assertThat(score.getValue())                  .as("Has score")                  .isEqualTo(8);    softAssertions.assertThat(score.getCombination())                  .as("Has combination")                  .isEqualTo(dice(1, 1, 3, 3));    softAssertions.assertThat(score.getReminder())                  .as("Has reminder")                  .isEqualTo(dice(5));} | 
  Нам не только не нужно помнить о вызове assertAll() но мы также можем видеть потенциальные ошибки в редакторе сравнения в IntelliJ: 
  Пользовательский SoftScoreAssertion 
Чтобы улучшить читаемость и возможность повторного использования проверки баллов, мы можем создать собственное утверждение, чтобы его можно было использовать следующим образом:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
 | 
@Testpublic void verifiesScoreSoftlyWithCustomAssertion() {    Score score = Score.scoreBuilder()                       .withValue(11)                       .withCombination(dice(1, 1, 3, 4))                       .withReminder(dice(6))                       .build();    SoftScoreAssertion.assertThat(score)                      .hasValue(8)                      .hasCombination(dice(1, 1, 3, 3))                      .hasReminder(dice(5))                      .assertAll();} | 
  SoftScoreAssertion использует SoftAssertions и поэтому мы все равно увидим все ошибки утверждений одновременно.  И код: 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
 | 
class SoftScoreAssertion extends AbstractAssert<SoftScoreAssertion, Score> {    private SoftAssertions softAssertions = new SoftAssertions();    protected SoftScoreAssertion(Score actual) {        super(actual, SoftScoreAssertion.class);    }    public static SoftScoreAssertion assertThat(Score actual) {        return new SoftScoreAssertion(actual);    }    public SoftScoreAssertion hasValue(int scoreValue) {        isNotNull();        softAssertions.assertThat(actual.getValue())                      .as("Has score")                      .isEqualTo(scoreValue);        return this;    }    public SoftScoreAssertion hasReminder(List<Dice> expected) {        isNotNull();        softAssertions.assertThat(actual.getReminder())                      .as("Has reminder")                      .isEqualTo(expected);        return this;    }   public SoftScoreAssertion hasCombination(List<Dice> expected) {        isNotNull();        softAssertions.assertThat(actual.getCombination())                      .as("Has combination")                      .isEqualTo(expected);        return this;    }    @Override    public SoftScoreAssertion isNotNull() {        softAssertions.assertThat(actual).isNotNull();        return this;    }    public void assertAll() {        this.softAssertions.assertAll();    }} | 
Ресурсы
- http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#soft-assertions
 - https://github.com/joel-costigliola/assertj-core/wiki/Creating-specific-assertions
 
Исходный код
- Исходный код этой статьи можно найти в моем демонстрационном проекте для юнитов на GitHub: https://github.com/kolorobot/unit-testing-demo .
 
| Ссылка: | AssertJ’s SoftAssertions — они нам нужны? от нашего партнера JCG Рафаля Боровца в блоге Codeleak.pl . | 
