Решение этого вопроса есть с коробки, я же хотел покодить в свое удовольствие и делюсь тем, что получилось.
Код лежит тут. Лицензия GNU GPL v3. На здоровье.
Если тебе лень писать @Test public void shouldBlahBlahBlah_whenBlahBlahBlah () {} для каждого отдельного ассерта, то скорее всего у тебя несколько ассертов в одном тесте. Так не рекомендуют делать, но это решение встречается достаточно часто. Почему? Просто потому что блок // given в этом конкретном тесте с 3-5-7ю ассертами может быть большим. А копипастить его в каждый отдельный тест чтобы уютно разместить там 1 assertEquals еще большее зло.
Да, конечно можно выделить // given часть теста в отдельный метод и повторно использовать. Только фигня получится. Вот был лаконичный тест: в // given подготовились, в // when вызвали одну строчку тестируемого метода, и в 3-5-7ю assertEquals проверили объект, который вернулся. И что? 1 тест. И следуя рекомендации 1 assert на 1 тест мы получаем кучу операторных скобок, 8 методов и 10 шагов в сторону от рекомендации - "тест как документация". Вот все было перед глазами, а теперь иди собирай все все мысли по классу.
И если ты не следуешь бездумно всем рекомендациям, описанным в инженерных книгах, то ты, так же как и я получишь один тест с 3-5-7ю ассертами. Но тут есть другой бок - скорее всего ты, так же как и я, утомился перезапускать этот один стройный тест. Да-да, интеграционный, блин, со спрингом под капотом, от чего он ранится не 10 милисекунд, а 100 секунд! Потому что мир джава жесток и беспощаден...
Решение созрело.
Да, я знаю, что писать несколько assertEquals в одном тесте (было) не ок. Но писать по новой конструкции для каждого ассерта тоже перебор.
Например вот тест, я в нем заведомо поломал первые 4 assert, заменив expected с true на false
Код лежит тут. Лицензия GNU GPL v3. На здоровье.
Если тебе лень писать @Test public void shouldBlahBlahBlah_whenBlahBlahBlah () {} для каждого отдельного ассерта, то скорее всего у тебя несколько ассертов в одном тесте. Так не рекомендуют делать, но это решение встречается достаточно часто. Почему? Просто потому что блок // given в этом конкретном тесте с 3-5-7ю ассертами может быть большим. А копипастить его в каждый отдельный тест чтобы уютно разместить там 1 assertEquals еще большее зло.
Да, конечно можно выделить // given часть теста в отдельный метод и повторно использовать. Только фигня получится. Вот был лаконичный тест: в // given подготовились, в // when вызвали одну строчку тестируемого метода, и в 3-5-7ю assertEquals проверили объект, который вернулся. И что? 1 тест. И следуя рекомендации 1 assert на 1 тест мы получаем кучу операторных скобок, 8 методов и 10 шагов в сторону от рекомендации - "тест как документация". Вот все было перед глазами, а теперь иди собирай все все мысли по классу.
И если ты не следуешь бездумно всем рекомендациям, описанным в инженерных книгах, то ты, так же как и я получишь один тест с 3-5-7ю ассертами. Но тут есть другой бок - скорее всего ты, так же как и я, утомился перезапускать этот один стройный тест. Да-да, интеграционный, блин, со спрингом под капотом, от чего он ранится не 10 милисекунд, а 100 секунд! Потому что мир джава жесток и беспощаден...
@SpringBootTest(classes = CodenjoyContestApplication.class, properties = "spring.main.allow-bean-definition-overriding=true") @RunWith(SpringRunner.class) @ActiveProfiles(SQLiteProfile.NAME) @Import(RestGameControllerTest.ContextConfiguration.class) @WebAppConfiguration public class RestGameControllerTest {...в этом тесте будет несколько assertEquals. И раз за разом, натыкаясь на очередной свалившийся ассерт, скорее всего ты, так же как и я, задавался вопросом: какого фига в junit тест валится после первого же ассерта?
Решение созрело.
Да, я знаю, что писать несколько assertEquals в одном тесте (было) не ок. Но писать по новой конструкции для каждого ассерта тоже перебор.
@Test public void shouldBlahBlah_whenBlahBlah() { ... }Вот и написал свой assertEquals который агрегирует ошибки и валидирует их только, когда ты явно этого попросишь в @After методе
@After public void checkErrors() { SmartAssert.checkResult(); }В простом вариаенте запуска потребуется еще всего лишь импортнуть класс, в котором есть статический assertEquals метод.
import static com.codenjoy.dojo.stuff.SmartAssert.*;
А старый импорт удалить
import static org.junit.Assert.*;
А что умного? Так это вывод результатов. Каждый тест отработает от начала и до конца, не важно сколько assertEquals по дороге не пройдут. При этом ты увидишь в консоли все expected: <qwe> but was: <asd> блоки и кусочек стектрейса из тестового класса, в котором были вызовы измененного assertEquals длинной до 10 строк (на это можно повлиять).Например вот тест, я в нем заведомо поломал первые 4 assert, заменив expected с true на false
@Test public void shouldExists() { assertEquals(false, service.exists("first")); assertEquals("false", get("/rest/game/first/exists")); assertEquals(false, service.exists("second")); assertEquals("false", get("/rest/game/second/exists")); assertEquals(false, service.exists("non-exists")); assertEquals("false", get("/rest/game/non-exists/exists")); }В оригинальной версии тест прекратил бы выполнение после первой же строчки. Слетел ассерт - давай до свидания. Но не co SmartAssert
org.junit.ComparisonFailure: expected:<[fals]e>; but was:<[tru]e>
com.codenjoy.dojo.web.rest.RestGameControllerTest.shouldExists(RestGameControllerTest.java:135)
org.junit.ComparisonFailure: expected:<[fals]e> but was:<[tru]e>
com.codenjoy.dojo.web.rest.RestGameControllerTest.shouldExists(RestGameControllerTest.java:136)
org.junit.ComparisonFailure: expected:<[fals]e> but was:<[tru]e>
com.codenjoy.dojo.web.rest.RestGameControllerTest.shouldExists(RestGameControllerTest.java:138)
org.junit.ComparisonFailure: expected:<[fals]e> but was:<[tru]e>
com.codenjoy.dojo.web.rest.RestGameControllerTest.shouldExists(RestGameControllerTest.java:139)
java.lang.AssertionError: There are errors
at org.junit.Assert.fail(Assert.java:88)
at com.codenjoy.dojo.stuff.SmartAssert.checkResult(SmartAssert.java:118)
at com.codenjoy.dojo.stuff.SmartAssert.checkResult(SmartAssert.java:132)
at com.codenjoy.dojo.web.rest.RestGameControllerTest.checkErrors(RestGameControllerTest.java:98)
Важно, что ссылки на сами ассерты в коде в idea кликабельны.
(RestGameControllerTest.java:139)
Так же я добился замены базовым проверятором Idea констукцииexpected:<[fals]e> but was:<[tru]e>
На такую, которая будет подсвечивать diff каждого слетевшего ассерта отдельно. В этом мне помог deprecated MultipleFailureException.
Интересная статья, спасибо.
ОтветитьУдалитьЕсть еще 1 вариант "из коробки" в junit 5 c использованием assertAll().
https://stackoverflow.com/questions/40796756/assertall-vs-multiple-assertions-in-junit5