├── .gitignore ├── PREREQUISITES.md ├── README.md ├── REVIEW.md ├── pom.xml ├── resources ├── application-architecture.puml ├── dummy.puml ├── fake.puml ├── mock.puml ├── spy.puml └── stub.puml └── src ├── main └── java │ └── com │ └── acme │ └── banking │ └── dbo │ ├── domain │ ├── Account.java │ ├── Branch.java │ ├── Cash.java │ ├── Client.java │ └── SavingAccount.java │ └── service │ ├── Processing.java │ └── Reporting.java └── test └── java └── com └── acme └── banking └── dbo └── ClientTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | 3 | ### Maven template 4 | target/ 5 | pom.xml.tag 6 | pom.xml.releaseBackup 7 | pom.xml.versionsBackup 8 | pom.xml.next 9 | release.properties 10 | dependency-reduced-pom.xml 11 | buildNumber.properties 12 | .mvn/timing.properties 13 | 14 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 15 | !/.mvn/wrapper/maven-wrapper.jar 16 | 17 | ### Java template 18 | # Compiled class file 19 | *.class 20 | 21 | # Log file 22 | *.log 23 | 24 | # BlueJ files 25 | *.ctxt 26 | 27 | # Mobile Tools for Java (J2ME) 28 | .mtj.tmp/ 29 | 30 | # Package Files # 31 | *.jar 32 | *.war 33 | *.nar 34 | *.ear 35 | *.zip 36 | *.tar.gz 37 | *.rar 38 | 39 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 40 | hs_err_pid* 41 | 42 | ### IDEA template 43 | .idea/ 44 | *.iml 45 | -------------------------------------------------------------------------------- /PREREQUISITES.md: -------------------------------------------------------------------------------- 1 | # Тренинг «Unit Testing & TDD»: подготовка 2 | 3 | # 1. Ожидания от участников 4 | Каждый участник перед началом: 5 | 6 | ## Информирован 7 | - Прочитал программу тренинга 8 | - Прочитал ожидания от участников 9 | 10 | ## В состоянии понять теоретическую часть 11 | - Понимает стиль OOAD: объектно-ориентированного анализа и проектирования 12 | - Выступает в роли разработчика или QA 13 | 14 | ## В состоянии пройти практическую часть 15 | - Имеет опыт коммерческой разработки от года 16 | - В состоянии читать и писать простой код на Java 17 | - В состоянии использовать git для коллективной разработки и ревью 18 | 19 | ## Вовлечен 20 | - Описывает текущую модель качества в проекте: желаемые метрики и свойства системы 21 | - Описывает текущую статистику по метрикам качества 22 | - Описывает текущий процесс обеспечения качества в проекте 23 | - Иллюстрирует кодовую базу автотестов (если есть) 24 | - Предлагают добавление новых тем, важных для проекта 25 | - Раставляет проектные приоритеты целей этого тренинга 26 | 27 | ## Замотивирован 28 | - Делится своими личными улучшениями качества системы 29 | - Делится своими личными улучшениями процесса обеспечения качества 30 | - Описывает текущие блокеры повышения качества 31 | - Формулирует волнующие вопросы по коду системы 32 | - Формулирует волнующие вопросы по коду автотестов 33 | - Формулирует волнующие вопросы по процессу автотестирования 34 | - Раставляет личные приоритеты целей этого тренинга 35 | - Предлагают добавление новых тем, важных для себя 36 | - Раставляет личные приоритеты программы этого тренинга 37 | 38 | # 2. Процесс подготовки 39 | 1. Участники заполняют опросник по ожиданиям от участников 40 | 2. Вебинар или очный воркшоп для 41 | - полного завершения списка ожиданий 42 | - выравнивания видения тренинга 43 | - понимания текущей культуры кода на производстве 44 | 45 | # 3. Ресурсный план тренинга 46 | ## Ограничения тренинга 47 | Максимальный размер группы – 12 участников 48 | 49 | ## Ресурсы аудитории 50 | - Рассадка участников по парам и один ноутбук/десктоп на пару 51 | - Флипчарт, маркеры для флипчарта, малярный скотч, стикеры – по пачке на пару участников 52 | - Проектор с входом HDMI 53 | 54 | ### Hardware 55 | RAM ≥ 8Гб 56 | 57 | ### Software 58 | 1. git client 59 | 1. JDK8 60 | 1. Maven 61 | 1. IDEA Ultimate (можно trial) 62 | 63 | ### Доступы тренера и участников из локальной сети 64 | 1. https://github.com:443 (с возможностью логина, pull и push) 65 | 1. https://mvnrepository.com:443 66 | 1. https://repo.maven.apache.org:443 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Тренинг «Unit Testing & TDD» 2 | ============================ 3 | 24 ак. часа, 18 астр. часов 4 | 5 | Цели тренинга 6 | ============ 7 | После тренинга участники смогут: 8 | ------------------------------- 9 | - [ ] Объяснить себе и менеджменту, где им нужны тесты, а где нет 10 | - [ ] Разрабатывать тесты как «спецификации на примерах» в роли документации 11 | - [ ] Разрабатывать поддерживаемые тесты и их наборы по модели 12 | - [ ] Подменять сложные компоненты системы на время тестирования 13 | - [ ] Анализировать тестовое покрытие для принятия решений по тест-дизайну 14 | - [ ] Обеспечивать поддерживаемый дизайн системы при помощи TDD 15 | 16 | В итоге бизнес получает: 17 | ------------------------ 18 | - [ ] Контролируемый cycle time задач 19 | - [ ] Контролируемое качество системы 20 | 21 | Программа 22 | ========= 23 | Зачем мы собрались? (1 часа всего / _из них_ 0.5 часа практики) 24 | --------------------------------------------------------------- 25 | - [ ] Обзор тренинга 26 | - [ ] О тренере 27 | - [ ] Разбивка по парам и знакомство-представление друг друга 28 | - [ ] Приоритезация целей тренинга и сбор проблем 29 | 30 | ### Fork and then clone codebase for further development 31 | ``` 32 | git clone --depth 1 -b http://github.com/eugene-krivosheyev/unit-testing-and-tdd 33 | ``` 34 | 35 | Что такое автотест? (1.5/0.5) 36 | ----------------------------- 37 | - [ ] Каковы цели и задачи _авто_ тестов? 38 | - [ ] В чем отличие от отладки? 39 | - [ ] Определение модуля и возможные виды модулей 40 | 41 | ### Live Coding Demo на примере "общеизвестного класса" 42 | - [ ] [Подключение основного фреймворка](https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven) 43 | - [ ] Понятие контракта по Б. Мейеру 44 | - [ ] Именование [тест-кейса/тест-класса и теста/тест-метода](https://junit.org/junit5/docs/current/user-guide/#writing-tests-classes-and-methods) 45 | - [ ] Понятие трасс выполнения (flows) и граничные условия 46 | - [ ] Подходы AAA и GWT из BDD 47 | - [ ] Роль фикстуры 48 | - [ ] [Забытый полуторный этап](https://junit.org/junit5/docs/current/user-guide/#writing-tests-assumptions) 49 | - [ ] Тест = фиксированная трасса выполнения 50 | - [ ] Тестовый набор = спецификация компонента 51 | 52 | ### Coding Iteration #01 53 | - [ ] Given legacy codebase with Client and SavingAccount domain types 54 | - [ ] When developers add guard clauses for creating Client and SavingAccount 55 | - [ ] And cover these components with maintainable autotests 56 | - [ ] Then coverage for these components should be ≥ 80% 57 | - [ ] And public code review should state for maintainability 58 | 59 | Как замерять тестовое покрытие? (0.5/0) 60 | --------------------------------------- 61 | - [ ] Понятие покрытия 62 | - [ ] Виды расчета покрытия 63 | - [ ] Инструменты расчета покрытия 64 | - [ ] Анализ текущего покрытия 65 | - [ ] Что покрывать в первую очередь в проектах? 66 | 67 | Как ускорить разработку автотестов за счет готовых фреймворков и библиотек? (1/0.5) 68 | ----------------------------------------------------------------------------------- 69 | - [ ] Подключение вспомогательных фреймворков: build tool 70 | - [ ] [Условное выполнение тестов](https://junit.org/junit5/docs/current/user-guide/#writing-tests-conditional-execution) 71 | - [ ] [Типизированные сравнения средствами основного фреймворка](https://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions) средствами основного фреймворка 72 | - [ ] [Типизированные сравнения средствами отдельного фреймворка](https://hamcrest.org/JavaHamcrest/tutorial) 73 | - [ ] [Типизированные сравнения средствами отдельного фреймворка](https://assertj.github.io/doc/) 74 | - [ ] [Исключения](https://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions) 75 | - [ ] [Таймауты](https://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions) 76 | - [ ] [Параметризованные тесты](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests) 77 | - [ ] [Расширения](https://junit.org/junit5/docs/current/user-guide/#extensions), в том числе [готовые](https://junit.org/junit5/docs/current/user-guide/#writing-tests-built-in-extensions) 78 | 79 | ### Coding Iteration #02 80 | - [ ] Given legacy codebase with Client and SavingAccount domain types 81 | - [ ] When developers add consistency rules for linking Client and SavingAccount 82 | - [ ] And cover these components with maintainable autotests 83 | - [ ] Then coverage for these components should be ≥ 90% 84 | - [ ] And public code review should state for maintainability 85 | 86 | Как писать интеграционные и модульные тесты? (1/0.5) 87 | ----------------------------------------------------- 88 | - [ ] В чем их специфика? [Системные vs Интеграционные vs Модульные](http://www.plantuml.com/plantuml/svg/JP112y8m38Nl-HLXT_-2Z3d4iw8NwI5sGOPREzgeYEo_cuuoUobvVL_w7gsZK93dEC14za5tnceVl1DsNOLVGBmUo7K31wEpzUFa7Jl1Iy_lnLPWftZmWy7D5ZEinWmpa1KVy1pr8Xq9o310Hq8tYenjyuzkT5YJyrkwjMRa7gLSx1E7Ls_P860XadFaoSTUQtpIOYaNkssCzgmrKx_W1m00) 89 | - [ ] Как по коду определить скоуп? 90 | - [ ] Виды тест-дублеров: [dummy](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuGf9BIvHqBLJ20uDuG9Y8BD2mQKqDxSImWFAW5HmEQJcfG2L0m00), [stub](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuGf9BIvHqBLJ20uDuG9YCBEaD8aBH2Ze8YJ0R91YBeVKl1IWJW00), [fake](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuGf9BIvHqBLJ20uDuKf9B4bCIYnELN1Bp4xb0ee09I1i4A6W2rK6n60sI2kNGsfU2j0S0000), [mock](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuGf9BIvHqBLJ20uDuG9Y4DCtFpaRB0xdEAJcfG0L0m00), [spy](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuGf9BIvHqBLJ20uDuG9YCBEWaWk8GKoNr8BKl9JKl18k60ke65a9GYUO3J8DOYHKaGDG4z0Q0000) 91 | - [ ] State-based testing VS Interaction-based testing 92 | - [ ] [Фреймворк тест-дублеров уровня объектов](https://site.mockito.org) и [интеграция с основным тестовым фреймворком](https://www.baeldung.com/mockito-junit-5-extension) 93 | - [ ] [Фреймворк тест-дублеров уровня REST-сервисов](http://wiremock.org/docs/getting-started/) 94 | - [ ] [Фреймворк тест-дублеров уровня REST-сервисов](https://www.mock-server.com) 95 | - [ ] Как среда сборки различает UT и IT 96 | 97 | ### Coding Iteration #03 98 | - [ ] Given legacy codebase with Processing component 99 | - [ ] When developers analyse and refactor production codebase for testability 100 | - [ ] And cover this component with maintainable _unit_ autotests 101 | - [ ] Then coverage for these component should be ≥ 90% 102 | - [ ] And public code review should state for maintainability 103 | 104 | Реализация фикстуры для обеспечения поддерживаемости тестов (1.5/1) 105 | ------------------------------------------------------------------- 106 | - [ ] [Когда и сколько раз создается объект тестового класса?](https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-instance-lifecycle) 107 | - [ ] Как максимально реюзать фикстуры? 108 | - Наследование тест-кейсов 109 | - [Методы жизненного цикла теста](https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations) 110 | - Fixture Builders 111 | 112 | ### Coding Iteration #04 113 | - [ ] Given test codebase 114 | - [ ] When developers analyse and refactor test codebase for maintainability 115 | - [ ] Then public code review should state for tests maintainability 116 | 117 | --- 118 | 119 | Как группировать тесты в наборы? (0.5/0) 120 | ---------------------------------------- 121 | - [ ] Зачем нужны test suites? 122 | - [ ] [Вложенные тесты](https://junit.org/junit5/docs/current/user-guide/#writing-tests-nested) 123 | - [ ] [Теги](https://junit.org/junit5/docs/current/user-guide/#writing-tests-tagging-and-filtering) и [запуск набора](https://howtodoinjava.com/junit5/junit5-test-suites-examples/) 124 | - [ ] Способ фильтрации средствами среды сборки [модульных](https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html) и [интеграционных](https://maven.apache.org/surefire/maven-failsafe-plugin/examples/inclusion-exclusion.html) тестов 125 | 126 | Как поддерживать качество тестов и снижать дублирование? (1/0.5) 127 | ---------------------------------------------------------------- 128 | ### Как обеспечить качество самих тестов? 129 | - [ ] Сначала поломанный тест 130 | - [ ] Анализ тестового покрытия 131 | - [ ] Ревью кода тестов 132 | - [ ] Mutation coverage 133 | 134 | ### Анти-паттерны разработки модульных тестов: "вредные советы" 135 | - [ ] Отношение к тестам не как к обычному коду 136 | - [ ] Большие расфокусированные тесты 137 | - [ ] Неговорящие имена 138 | - [ ] Дублирование фикстуры 139 | - [ ] Стопроцентное покрытие 140 | 141 | ### Coding Iteration #05 142 | - [ ] Given test codebase 143 | - [ ] When developers analyse and refactor test codebase for maintainability 144 | - [ ] Then cross-team code review should state for tests maintainability 145 | 146 | Как обеспечить тестопригодность дизайна legacy системы? (1.5/0.5) 147 | ----------------------------------------------------------------- 148 | - [ ] Как оценить тестопригодность legacy code? 149 | - [ ] Метрика Coupling 150 | - [ ] Метрика Cohesion 151 | - [ ] Понятность/осознаваемость 152 | - [ ] Каков тестопригодный дизайн? 153 | 154 | ### Live Coding Demo для реализации компонента Reporting и нового CheckingAccount 155 | - [ ] Принципы проектирования SOLID 156 | - [ ] Шаблоны Factory и DI 157 | - [ ] Шаблоны Strategy/State 158 | - [ ] Ключевая диллема покрытия legacy code? 159 | 160 | ### Coding Iteration #06 161 | - [ ] Given legacy codebase with Reporting component 162 | - [ ] When developers implement polymorphic testable implementation for Reporting and CheckingAccount 163 | - [ ] Then cross-team code review should state for its testability 164 | 165 | --- 166 | 167 | Какую ценность дает практика TDD? (0.5/0) 168 | ----------------------------------------- 169 | - [ ] Что такое TDD? 170 | - [ ] TDD как практика проектирования 171 | - [ ] Зачем нужен TDD? 172 | - [ ] Минимизация отладки 173 | - [ ] Снижение затрат на инкрементальную разработку 174 | - [ ] Быстрая обратная связь 175 | - [ ] Повышение поддерживаемости дизайна 176 | - [ ] Удобство API "из коробки" 177 | - [ ] Тесты как документация 178 | - [ ] Предсказуемость поставки 179 | - [ ] Чистый работающий код 180 | - [ ] Управление страхом 181 | 182 | В каком ритме писать по TDD? (1.5/0.5) 183 | -------------------------------------- 184 | - [ ] Red – Green – Refactor 185 | - [ ] Скорость отработки тестового набора как предусловие практики TDD 186 | 187 | ### Live Coding Demo для компонента Branch 188 | - [ ] Операция добавления в branch 189 | 190 | ### Coding Iteration #07 191 | - [ ] Given legacy codebase with Branch domain type 192 | - [ ] When developers implement full-functional Branch implementation 193 | - [ ] And made it through TDD cycles 194 | - [ ] Then coverage for this component should be 100% 195 | - [ ] And public code review should state for maintainability 196 | 197 | [Базовые шаблоны TDD](https://gist.github.com/jameshwang/5335032) (1.5/1) 198 | ------------------------------------------------------------------------------------ 199 | - [ ] Test First 200 | - [ ] Isolated Tests 201 | - [ ] Assertion First 202 | - [ ] Test Data 203 | - [ ] Child Test 204 | - [ ] Test List 205 | - [ ] Mock Object 206 | - [ ] Crash Test Dummy 207 | 208 | ### Coding Iteration #08 209 | - [ ] Given legacy codebase with Reporting service 210 | - [ ] When developers implement reporting operation for branch 211 | - [ ] And made it through TDD cycles 212 | - [ ] Then coverage for this component should be 100% 213 | - [ ] And coverage for this component should state this is _unit_ tests 214 | - [ ] And public code review should state for maintainability 215 | 216 | Шаблоны красной и зеленой полосы (1.5/1) 217 | ---------------------------------------- 218 | ### Красной полосы 219 | - [ ] One-step Test 220 | - [ ] Starter Test 221 | - [ ] Another Test 222 | - [ ] Regression Test 223 | 224 | ### Зеленой полосы 225 | - [ ] Obvious Implementation 226 | - [ ] Triangulation 227 | - [ ] One to Many 228 | 229 | ### Coding Iteration #09: TDD Ping-pong 230 | - [ ] Given legacy codebase with Reporting service 231 | - [ ] When developers implement reporting operations 232 | - [ ] And made it through TDD cycles in pair ping-pong rules 233 | - [ ] Then coverage for this component should be 100% 234 | - [ ] And coverage for this component should state this is _unit_ tests 235 | - [ ] And public code review should state for maintainability 236 | 237 | Как внедрить UT&TDD в процесс разработки? (0.5/0) 238 | ------------------------------------------------- 239 | ### Каковы затраты на UT&TDD? 240 | - [ ] Постановка экономической задачи 241 | 242 | ### Типовые ошибки TDD 243 | - [ ] Code First 244 | - [ ] Too Many Obvious Implementation 245 | - [ ] Too Many Triangulations 246 | - [ ] Coverage Affinity 247 | - [ ] Implementation Testing but not Contract Testing 248 | 249 | ### Как внедрить? 250 | - [ ] Общение с менеджментом 251 | - [ ] Secure sandbox 252 | - [ ] Последовательное расширение scope 253 | 254 | Финальная ретроспектива (1/0.5) 255 | ------------------------------- 256 | - [ ] План конкретных ближайших действий 257 | 258 | Буфер (2) 259 | --------- 260 | - [ ] Auto-testing and DB: patterns 261 | - [ ] Test data generation: [mockaroo](https://www.mockaroo.com), [generatedata](http://generatedata.com), [10](https://www.softwaretestinghelp.com/test-data-generation-tools/) and [15](https://www.guru99.com/test-data-generation-tools.html) tools, [Faker](https://github.com/joke2k/faker), [PG](https://pgcodekeeper.readthedocs.io/ru/latest/mock_data.html), [not only db](https://quality-lab.ru/blog/8_services_for_data_generation/) 262 | -------------------------------------------------------------------------------- /REVIEW.md: -------------------------------------------------------------------------------- 1 | # Тренинг «Unit Testing & TDD»: анализ результатов 2 | Активности после тренинга: 3 | 4 | # 1. Персональные вопросы тренеру 5 | Каждый участник в процессе применения знаний и навыков пишет тренеру: 6 | - Какие идеи и концепции вступили в противоречие с практикой 7 | - Какие трудности испытывает при практической реализации навыков 8 | - Запрос на Code Review в неясных и трудных случаях 9 | - Какие личные достижения, по мнению участника, реализованы 10 | - Какие возникли идеи по улучшению процесса разработки 11 | 12 | # 2. Групповое ревью и ретроспектива 13 | - Как поменялся процесс разработки 14 | - Как поменялся mindset участников 15 | - Как поменялись метрики качества системы 16 | - Какие личные достижения можно зафиксировать 17 | - Какие выявились блокеры внедрения новых практик 18 | - Code Review автотестов и кода системы 19 | - Какие дальнейшие шаги по улучшению 20 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.acme.banking 6 | dbo 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-compiler-plugin 19 | 3.11.0 20 | 21 | 17 22 | 17 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-surefire-plugin 28 | 3.0.0-M9 29 | 30 | 31 | true 32 | 33 | 34 | 35 | 36 | org.jacoco 37 | jacoco-maven-plugin 38 | 0.8.8 39 | 40 | ${basedir}/target/coverage-reports/jacoco-unit.exec 41 | ${basedir}/target/coverage-reports/jacoco-unit.exec 42 | 43 | java/lang/* 44 | java/util/* 45 | 46 | 47 | 48 | 49 | jacoco-initialize 50 | 51 | prepare-agent 52 | 53 | 54 | 55 | jacoco-site 56 | package 57 | 58 | report 59 | 60 | 61 | 62 | 63 | 64 | org.pitest 65 | pitest-maven 66 | 1.11.4 67 | 68 | 69 | org.pitest 70 | pitest-junit5-plugin 71 | 1.1.2 72 | 73 | 74 | 75 | 76 | com.acme.* 77 | 78 | 79 | com.acme.* 80 | 81 | 82 | 83 | 84 | mutation-coverage 85 | 86 | mutationCoverage 87 | 88 | 89 | 90 | mutation-report 91 | 92 | report 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | org.junit.jupiter 103 | junit-jupiter-engine 104 | 5.9.2 105 | test 106 | 107 | 108 | org.hamcrest 109 | hamcrest-library 110 | 2.2 111 | test 112 | 113 | 114 | org.assertj 115 | assertj-core 116 | 3.24.2 117 | test 118 | 119 | 120 | org.mockito 121 | mockito-core 122 | 5.2.0 123 | test 124 | 125 | 126 | org.mockito 127 | mockito-junit-jupiter 128 | 5.2.0 129 | test 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /resources/application-architecture.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | package "Frontend" { 3 | [Handler] 4 | component View { 5 | [Control] -> Handler 6 | } 7 | } 8 | actor User 9 | User -> Control 10 | 11 | database DB 12 | package "Backend" { 13 | Handler -> [Controller] 14 | [Controller] -> [Service] 15 | [Service] -> [Repository] 16 | [Repository] -> [DB] 17 | } 18 | @enduml 19 | -------------------------------------------------------------------------------- /resources/dummy.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | Test -> SUT 3 | SUT ->x Dummy 4 | SUT --> Test 5 | @enduml -------------------------------------------------------------------------------- /resources/fake.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | Test -> SUT 3 | database Fake 4 | SUT -> Fake 5 | Fake --> SUT 6 | SUT --> Test 7 | @enduml 8 | -------------------------------------------------------------------------------- /resources/mock.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | Test -> SUT 3 | SUT -> Mock 4 | Test -> Mock 5 | @enduml 6 | -------------------------------------------------------------------------------- /resources/spy.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | Test -> SUT 3 | SUT -> Spy 4 | Spy -> Dependent 5 | Dependent --> Spy 6 | Spy --> SUT 7 | SUT --> Test 8 | Test -> Spy 9 | @enduml 10 | -------------------------------------------------------------------------------- /resources/stub.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | Test -> SUT 3 | SUT -> Stub 4 | Stub --> SUT 5 | SUT --> Test 6 | @enduml -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/domain/Account.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.domain; 2 | 3 | public interface Account { 4 | int getId(); 5 | double getAmount(); 6 | Client getClient(); //TODO reference integrity 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/domain/Branch.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.domain; 2 | 3 | import java.util.Collection; 4 | 5 | import static java.util.Collections.unmodifiableCollection; 6 | 7 | public class Branch { 8 | private Collection accounts; //TODO 9 | 10 | public Branch(Collection accounts) { 11 | this.accounts = accounts; 12 | } 13 | 14 | public Collection getAccounts() { 15 | return unmodifiableCollection(accounts); 16 | } 17 | 18 | public Collection getChildren() { 19 | return null; //TODO 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/domain/Cash.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.domain; 2 | 3 | public class Cash { 4 | public static void log(double amount, int fromAccountId) { 5 | //TODO 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/domain/Client.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.domain; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | 6 | public class Client { 7 | private int id; 8 | private String name; 9 | private Collection accounts = new ArrayList<>(); //TODO 10 | 11 | public Client(int id, String name) { 12 | this.id = id; 13 | this.name = name; 14 | } 15 | 16 | public int getId() { 17 | return id; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/domain/SavingAccount.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.domain; 2 | 3 | public class SavingAccount implements Account { 4 | private int id; 5 | private Client client; 6 | private double amount; 7 | 8 | public SavingAccount(int id, Client client, double amount) { 9 | this.id = id; 10 | this.client = client; 11 | this.amount = amount; 12 | } 13 | 14 | @Override 15 | public double getAmount() { 16 | return amount; 17 | } 18 | 19 | @Override 20 | public int getId() { 21 | return id; 22 | } 23 | 24 | @Override 25 | public Client getClient() { 26 | return client; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/service/Processing.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.service; 2 | 3 | import com.acme.banking.dbo.domain.Account; 4 | import com.acme.banking.dbo.domain.Cash; 5 | import com.acme.banking.dbo.domain.Client; 6 | 7 | import java.util.Collection; 8 | 9 | public class Processing { 10 | public Client createClient(String name) { 11 | return null; //TODO 12 | } 13 | 14 | public Collection getAccountsByClientId(int clientId) { 15 | return null; //TODO 16 | } 17 | 18 | public void transfer(int fromAccountId, int toAccountId, double amount) { 19 | //TODO 20 | } 21 | 22 | public void cash(double amount, int fromAccountId) { 23 | Cash.log(amount, fromAccountId); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/acme/banking/dbo/service/Reporting.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo.service; 2 | 3 | import com.acme.banking.dbo.domain.Branch; 4 | 5 | public class Reporting { 6 | /** 7 | * @return Markdown report for all branches, clients, accounts 8 | */ 9 | public String getReport(Branch rootBranch) { 10 | return null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/acme/banking/dbo/ClientTest.java: -------------------------------------------------------------------------------- 1 | package com.acme.banking.dbo; 2 | 3 | import com.acme.banking.dbo.domain.Client; 4 | import org.junit.jupiter.api.Disabled; 5 | import org.junit.jupiter.api.DisplayName; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertAll; 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | import static org.junit.jupiter.api.Assumptions.*; 11 | 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.*; 14 | import static org.hamcrest.beans.HasPropertyWithValue.hasProperty; 15 | 16 | 17 | @DisplayName("Test suite") 18 | public class ClientTest { 19 | @Test @Disabled("temporary disabled") 20 | @DisplayName("Test case") 21 | public void shouldStorePropertiesWhenCreated() { 22 | //region given 23 | final int clientId = 1; 24 | final String clientName = "dummy client name"; 25 | //endregion 26 | 27 | //region when 28 | Client sut = new Client(clientId, clientName); 29 | assumeTrue(sut != null); 30 | //endregion 31 | 32 | //region then 33 | //Junit5: 34 | assertAll("Client store its properties", 35 | () -> assertEquals(clientId, sut.getId()), 36 | () -> assertEquals(clientName, sut.getName()) 37 | ); 38 | 39 | //Hamcrest: 40 | assertThat(sut, 41 | allOf( 42 | hasProperty("id", notNullValue()), 43 | hasProperty("id", equalTo(clientId)), 44 | hasProperty("name", is(clientName)) 45 | )); 46 | 47 | //AssertJ: 48 | org.assertj.core.api.Assertions.assertThat(sut) 49 | .hasFieldOrPropertyWithValue("id", clientId) 50 | .hasFieldOrPropertyWithValue("name", clientName); 51 | //also take a look at `extracting()` https://stackoverflow.com/a/51812188 52 | //endregion 53 | } 54 | } 55 | --------------------------------------------------------------------------------