owned this note
owned this note
Published
Linked with GitHub
# Testing
## Design by Contract
DbC - это подход к дизайну кода. Его хочется использовать для тестирования (и верификации), но на практике есть несколько сложностей:
* Несовершенные тулзы, версии Джава меняются, а тулзы не поспевают за изменениями
* Насыщение кода встроенными сложными проверками контрактов (pre/post-conditions, invariants) - идея очень интересная. Но на практике, проверки будут менять состояние объектов, а значит возрастает риск, что система будет по разному работать с включенными и выключенными проверками.
* Трудно реализовать сложные проверки. Нужен ghost код, вспомогательные методы, которые усложняют код. В традиционном подходе к тестированию это просто все выносится в отдельный тестовый код. В случае DbC это может стать очень неудобно, и "замусорить" код всяким вспомогательным хламом.
## Общий подход к тестированию
Есть две ключевые активности: написание test oracles и генерация тест кейсов.
### Test oracles
Т.е. реализация всеразличных проверок, что код работает правильно. Очень часто это выглядит как еще одна реализация, но удобная с точки тестирования. Например, можно написать реализацию в чистом функциональном стиле, без мутации состояния (один из ключевых источников проблем). Часто можно избежать необходимости делать сложную оптимизацию производительности (еще один мощный источник багов).
### Генерация test case'ов
Тест кейс есть конкретный набор параметров, которые воспроизводят ту или иную тестовую ситуацию. Соответственно, при наличии тестового оракла, можно проверить правильность поведения реализации в том или ином случае.
На данный момент, хорошо развиты средства (полу)автоматической генерации тестовых случаев, что имеет смысл использовать.
### Инжекция test oracles
Как писалось выше, DbC выглядит как привлекательный инструмент для внедрения проверок в код. В частности, таким проверкам доступно больше инфы, что облегачает их реализацию. В частности, JML дает доступ к версии состояния до вызова метода.
Однако, на практике с DbC в качестве тестирования есть проблемы (см выше и ниже).
Другие варианты:
* стандартное тестирование, когда тестовый код вынесен в отдельный софтверный модуль
* test doubles - замена продакшн объектов для более удобного тестирования. Mocks, Dummies, Spies, etc. См подробнее [тут](https://martinfowler.com/bliki/TestDouble.html)
* Инжекция с помощью Aspect Oriented Programming, например [AspectJ](https://en.wikipedia.org/wiki/AspectJ)
### Автоматизация генерации тестов
Есть более-менее зрелые тулзы для генерации тестов, которые имеет смысл использовать.
* [Randoop](https://randoop.github.io/randoop/) - живая тулза, последний релиз 21 Апреля 2019 года. Требует аннотаций к коду, генерирует случайные последовательности вызовов методов.
* [JDoop](https://github.com/psycopaths/jdoop) тулза активно не разрабатывается, но это по сути есть питонья обвязка к Randoop и [JDart](https://github.com/psycopaths/jdart). Последнее есть concolic движок для Джава, который позволяет варьировать пути исполнения кода (т.е. генерировать параметры которые приведут к новому пути исполнения кода).
* Тулзы на основе property-based testing, аля [QuickCheck](https://en.wikipedia.org/wiki/QuickCheck), адаптированные для Java. Если пройти по ссылке, там упоминается 7 реализаций для Джава. Кроме того, можно использовать и реализации для других JVM языков (Scala, Kotlin, Groovie, etc).
* [Alloy](http://alloytools.org/) - вообще говоря, язык модеирования, но его широко используют для тестирования и ограниченной верификации, в том числе, протоколы, криптография, тестирования софта. Потенциально очень полезный, ибо быстро перебирает всякие варианты.
#### Pairwise testing
* [AllPairs](https://github.com/thombashi/allpairspy/) - Python, достаточно простой
* [JCUnit](https://github.com/dakusui/jcunit) навороченный, развивается, Java, unit тестирование
* [Tcases](https://github.com/cornutum/tcases) навороченный, Java, ориентирован не только на Unit тестирование, но на генерацию тестов и для интегрейшн и системного тестирования тоже. Работает с json и xml описаниями. Что не очень удобно для юнитов, но норм для интеграционного и системного уровня
* [PICT](https://github.com/microsoft/pict) Микрософтовский тул, вроде крутой, CLI тулза
* Еще куча есть [тут](http://www.pairwise.org/tools.asp)
### Язык программирования для тестирования
Для целей тестирования, как для написания тестовых ораклов, так и для генерации тестов, так и для общей автоматизации, можно использовать не только Java, но и другие JVM языки. Ибо они зачастую гораздо более выразительны (Scala, Kotlin, Groovie), а некоторое снижение производительности, например, из-за использования функциональных идиом, не так критично для тестирования.
По сути, вышеприведенные языки хорошо поддерживают создание DSL (в отличие от Java), что активно используется и для тестирования, т.е. testing DSL.
# Design by contract
## Интро
Хорошая отправная точка - почитать [статью в Wikipedia](https://en.wikipedia.org/wiki/Design_by_contract).
Еще хороший [линк](http://www.valid4j.org/concepts.html).
Подробнее в контексте Джава можно почитать тут: http://www.eecs.ucf.edu/~leavens/JML//jmldbc.pdf и http://www.eecs.ucf.edu/~leavens/JML/fmco.pdf.
Еще интересная сери статей, там тулзы разбираются.
https://www.leadingagile.com/2018/05/design-by-contract-part-one/
https://www.leadingagile.com/2018/05/design-by-contract-part-two/
https://www.leadingagile.com/2018/05/design-by-contract-part-three/
Вывод аффтара (вторая сцыла)
> There are quite a few other DbC implementations for Java, but they are either incomplete, unreliable, or unsupported. Unfortunately, there appear to be no viable DbC libraries for Java at this time; just a few dead or dying projects and some non-starters. A shame.
## Чем полезно
Design by contract - подход к дизайну софта.
Он подразумевает явное специфицирование, как должен вести себя код: pre-conditions, post-conditions, invariants.
Это полезно с точки зрения дисциплины проектирования, а так же мы получаем хорошую документацию, которая более-менее строго описывает намерения проектировщика.
Кроме того, на основе DbC стоится широкий набор тулзов, который позволяет проверять соблюдения спецификации, либо с помощью инструментирования кода (расширенные assertions), либо символическое исполнение, вплоть до формальной верификации кода (подможество языка обычно).
Также есть тулзы которые генерируют тест кейсы.
## DbC и тестирование
DbC может быть хорошим инструментом, дополняющим тестирования.
Run-time проверялки (pre-, post-conditions, invariants) могут служить как test oracle тестов. При этом, их можно задействовать почти при любом виде тестирования, как при юнит тестировании, так и при компонент/интегрейшн тестировании, так и при тестировании системы в целом.
Нужен только источник тестовых ситуаций (это может быть как систематическое, так и fuzzy тестирование на разных уровнях).
## Поддержка в Java
### JML
Основные реализации DbC в Java строятся вокруг [JML](https://en.wikipedia.org/wiki/Java_Modeling_Language).
Есть херова туча тулзов, но к сожалению, большинство тулзов не поддерживают Java 8.
[OpenJML](http://www.openjml.org/) поддерживает java 8, и может даже автоматически находить расхождения со спецификацией (выполнять символическое тестирования, грубо говоря). Но все равно он поддерживает частично, с ограничениями.
Есть автоматическая генерилка тестов [JMLUnitNG](http://insttech.secretninjaformalmethods.org/software/jmlunitng/), к сожалению, заброшенная, но поддерживающая более-менее позднюю джаву.
### Other
Wikipedia говорит о следующих активных проектах:
* [OVal](http://oval.sourceforge.net/)
* [Cofoja](https://github.com/nhatminhle/cofoja)
* [valid4j](http://www.valid4j.org/)