The document discusses techniques for writing tests that are easy to write and maintain. It begins by outlining common problems with unit testing like tests being difficult to understand, requiring a lot of boilerplate code, and being brittle to minor code changes. The rest of the document proposes solutions to these problems like using a Given/When/Then structure to increase readability, implementing entity builders and trainers to reduce boilerplate code, loosely coupling tests to the code under test to prevent fragile tests, and abstracting external dependencies to speed up test execution. The overall message is that with the right testing patterns and structure, tests can be designed to be maintainable and enjoyable to write.
3. What does this test check?
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 3
4. What does this test check?
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 4
Call to component under test (CUT)
Configuration of mocked objects
Verification
Set the next user id
Set the next activation code
Register new user
Verify email sent
Verify user saved
5. Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 5
Too much boilerplate code
• Tests are hard to understand
• Writing tests is a lot of effort
The Fragile Test Problem
• Adjusting tests after a minor change
takes two days
• Tests generate too many false positives
Tests are running too long
à No one likes writing tests
https://imgs.xkcd.com/comics/compiling.png
Common Problems with Unit Testing
6. Okay, no one likes writing tests. So what?!
The consequences of a bad test structure (simplified)
Write tests you love, not hate | Jens Happe | Chrono24 6
Sep-23
7. What if…
The consequences of a good test structure (simplified)
Write tests you love, not hate | Jens Happe | Chrono24 7
Sep-23
8. Sep-23
Agenda
Common problems with Unit Testing
Increase readability
by getting the basics right
Reduce boilerplate code
by using Trainers and Entity Builders
Resolve the Fragile Test Problem
by decoupling tests and implementation
Speed up slow tests
by abstraction of the platform
9. Increase readability
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 9
http://xunitpatterns.com/Test%20Utility%20Method.html
https://cucumber.io/docs/gherkin/reference/
when
given
then
Set the next user id
Set the next activation code
Register new user
Verify email sent
Verify user saved
Extract method with Given / When / Then
10. Increase readability
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 10
Extract method with Given / When / Then
when
given
then
https://martinfowler.com/bliki/GivenWhenThen.html
11. Increase readability
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 11
Explicit relationship between Given and Then
when
given
then
13. So, we are done now, right?
Thank you for your attention!
It was a pleasure J
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 13
14. Of course not.
• Our Test Class is still a mess
containing almost only
boiler plate code.
• We cannot reuse the given…
and then… methods for
other test cases.
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 14
Test Boilerplate
15. Sep-23
Agenda
Common problems with Unit Testing
Increase readability
by getting the basics right
Reduce boilerplate code
by using Trainers and Entity Builders
Resolve the Fragile Test Problem
by decoupling tests and implementation
Speed up slow tests
by abstraction of the platform
16. Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 16
Entity Builders simplify test setup
https://github.com/casid/jusecase-builders-generator
17. Trainers
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 17
Problem: Configuring mocked objects is very repetitive and verbose
18. Trainers
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 18
Encapsulate the configuration in separate classes called Trainers
19. Trainers
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 19
Encapsulate the configuration in separate classes called Trainers
…
20. Trainers
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 20
Encapsulate the configuration in separate classes called Trainers
…
21. Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 21
• Configuration of mocked objects outside of the test classes
-> increased readability
-> increased reusability
• Generic Trainers can be developed, that further simplify the test setup
Trainers
Benefits
23. Sep-23
Agenda
Common problems with Unit Testing
Increase readability
by getting the basics right
Reduce boilerplate code
by using Trainers and Entity Builders
Resolve the Fragile Test Problem
by decoupling tests and implementation
Speed up slow tests
by abstraction of the platform
32. Fragile Test Problem
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 32
Tight Coupling = Bad Design
33. Fragile Test Problem
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 33
Solution: Loosely coupled tests
https://blog.cleancoder.com/uncle-bob/2017/10/03/TestContravariance.html
34. Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 34
Fragile Test Problem
Solution: Loosely coupled tests
https://blog.cleancoder.com/uncle-bob/2017/10/03/TestContravariance.html
35. That breaks the rules!
For every class X there should
be a test class XTest.
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 35
But wait.
Fragile Test Problem
36. Isn’t that indirect testing?
Typical example for indirect
testing: Testing through the
presentation layer
No. Here we test the result of
the interaction between the
services, not individual
services.
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 36
But wait.
Fragile Test Problem
http://xunitpatterns.com/Obscure%20Test.html#Indirect%20Testing
37. It's much harder now to
identify the cause of a failing
test!
No. You should work in small
increments and run tests after
every change.
That makes it easy to identify
the cause of a failing test.
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 37
But wait.
Fragile Test Problem
39. Sep-23
Agenda
Common problems with Unit Testing
Increase readability
by getting the basics right
Reduce boilerplate code
by using Trainers and Entity Builders
Resolve the Fragile Test Problem
by decoupling tests and implementation
Speed up slow tests
by abstraction of the platform
40. Speed up slow tests
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 40
External dependencies slow down test execution
41. Speed up slow tests
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 41
Push all external dependencies outside and only test the logic
• Dependency Rule
• Outside concrete, inside
abstract
-> Intrinsically testable
42. Speed up slow tests
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 42
However, the reality is messy.
43. Speed up slow tests
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 43
However, the reality is messy. So, let’s deal with it.
45. Our journey
2003 – 2016
• Almost no automated tests
2016 – 2018
• Test-Driven Development ideas
• Entity Builder and Trainer
• Establishment of use case tests
2019
• Move from Jenkins to GitLab CI
• Run tests with every push
2022
• Monorepo with parallel build
2023
à 11.935 use case (unit) tests that run in less than a minute
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 45
… until now
46. • Removing and simplifying supporting frameworks to run tests
à Fast test execution
Separating tests from external dependencies
• Testing at the borders of what matters at this point
à Tests and implementation can be structured independently
Decoupling test and implementation
• Entity Builders allow clear data definition
• Trainers simplify the configuration of dependencies
à Reusable and simple setup
Defining scenarios simplified
• Given / When / Then gives structure
• Explicit relationship between pre- and post-condition
à Increased readability
Getting the basics right
Sep-23 Write tests you love, not hate | Jens Happe | Chrono24 46
Key Takeaways
47. Many people contributed to this work:
• Andreas Hager
• Niklas Keller
• Martin Hofmann-Sobik
• And many others…
Email:
jens.happe@chrono24.com
X / Twitter:
@HappeJens
LinkedIn:
https://www.linkedin.com/in/jens-happe-idea-to-impact/
Thank you!
Maybe you? Join us!
https://about.chrono24.com/jobs/technology/