Одно из правил написания хорошего модульного теста состоит в том, что он должен потерпеть неудачу по одной причине, поэтому модульный тест должен проверить одну логическую концепцию. Иногда довольно сложно иметь одно утверждение на тест. Чтобы следовать правилу, мы можем иметь несколько утверждений на объект в одном тесте.
Однако проблема с несколькими утверждениями в одном тесте заключается в том, что если первое по какой-либо причине не удается, мы фактически не знаем о других утверждениях, поскольку они не будут выполнены. И вы знаете упражнение: вы проверяете причину ошибки утверждения, исправляете ее и повторно запускаете тест. Может быть, вам повезет, и испытание пройдет. Но, может быть, это не удастся с другим утверждением. С очень быстрыми юнит-тестами это не является большой проблемой, но когда дело касается, например, анализа тестов 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
|
@Test public 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 : 8 Actual : 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
|
@Test public 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
|
@Rule public JUnitSoftAssertions softAssertions = new JUnitSoftAssertions(); @Test public 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
|
@Test public 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 . |