Как правильно писать ассерты

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Поговорим теперь об ассертах

Ассерты — одна из само собой разумеющихся вещей, поэтому все тут, казалось бы, специалисты. Кто-то пользуется встроенными в Java или в Junit, кто-то пользуется продвинутыми библиотеками, кто-то сооружает собственную.

Но попробуем подойти к этому более серьезно. Как, на самом деле, правильно?

Во-первых, ассерты дублируют спецификацию. Если в спецификации указан shouldReturnValidOrder, то и проверять нужно именно это, а не assertNotNull.

Во-вторых, ассерты должно быть легко читать. Т.е., мгновенно, сопоставляя со спецификацией.

Если ассертов слишком много (на мой крайний вкус много это больше одного, но поставим ограничение хотя бы в пять-семь), то тест перестает быть понимаемым. По хорошему, у каждого теста должна быть только одна причина упасть.

Ассерты могут быть направлены на: примитивное поле, объект, коллекцию, редко функцию или thunk.

Чем сложнее объект, тем сложнее и разнообразнее будут ассерты, и тем сложнее их будет читать и находить ошибки.

Положительные утверждения читаются лучше двойных отрицательных.

Стандартные методы читаются лучше кастомных хелперов. (Кто знает, кто и где тестировал библиотеку хелперов). И ассерты должны находиться в теле тестового метода, а не где-то в глубине тестовых хелперов (сонар справедливо ругается на отсутствие ассертов).
Ассерты о полях понятнее, чем ассерты об объектах и уж тем более о коллекциях.

В случае вложенных полей имеет смысл тестировать полностью

не
assertNotNull(order.getCustomer().getName)

а
assertNotNull(order)
assertNotNull(order.getCustomer())
assertNotNull(order.getCustomer().getName())


Ассерты не просто тупо проверяют то, что возвращается из метода, а влияют на это. И если в наших силах это поменять, то нужно поменять.

Относительно сложно делать утверждения о коллекциях. Содержат ли они нули, отсортированы ли они, как именно отсортированы, как именно проверяется равенство элементов и т.д. — все это делает коллекции трудными объектами для ассертов, особенно когда в методе присутствует и логика относящаяся к элементам коллекций.

Поэтому метод типа
List<Order> getOrderList(List<OrderDao> orderDaoList){
        return orderDaoList.stream().map(orderDao=>order.name(orderDao.getName).build()).collect(Collectors.toList())
}


легко разбить на два, один трансформер orderDao=>order и протестировать его отдельно, а второй будет тестировать маппинг коллекций на абстрактном маппере, и мы сможем его простестировать на заглушке.

List<Order> getOrderList(List<OrderDao> orderDaoList, OrderDaoToOrderMapper mapper){
        return orderDaoList.stream().map(mapper::map).collect(Collectors.toList())
}


С другой стороны, коллекции хорошо поддаются типизации и расширению, т.е. мы относительно легко можем сделать коллекцию собственного типа со всеми проверенными свойствами, ко- и контравариантностью и тп. Поэтому вместо generic List мы могли бы сделать свой собственный OrderList, или OrderSet, или OrderSortedSet, и чем специфичнее, тем лучше. И тесты станут проще.

Делать утверждения о функциях не намного сложнее, чем об объектах, и они в некоторых языках хорошо типизируются, поэтому можно разве что посоветовать лучшую типизацию, т.е. вместо Func <Order,Order> возвращать какой-нибудь OrderComparator.
Источник: https://habr.com/ru/post/475276/


Интересные статьи

Интересные статьи

В этой статье мы рассмотрим, как система управления 1С-Битрикс справляется с большими нагрузками. Данный вопрос особенно актуален сегодня, когда электронная торговля начинает конкурировать по обороту ...
Недавно пришлось мне опять/снова погрузиться в чудесный мир программирования Linux скриптов. В принципе, дело не очень хитрое, но поскольку мне попадаются такие задачи не часто, то каждый раз и...
Возможность интеграции с «1С» — это ключевое преимущество «1С-Битрикс» для всех, кто профессионально занимается продажами в интернете, особенно для масштабных интернет-магазинов.
В 1С Битрикс есть специальные сущности под названием “Информационные блоки, сокращенно (инфоблоки)“, я думаю каждый с ними знаком, но не каждый понимает, что это такое и для чего они нужны
Тут у нас возник спор: нужно ли писать [weak self] в GCD? Один говорит: – [weak self] нужно писать везде! Второй говорит: – Нет, даже если не писать [weak self] внутри DispatchQueue, утечк...