The Art of Unit Testing
The Circle of Purity
Check out my ‘Clean Code – The Next Episode’
Deep Dive at Devoxx BE 2019 for more context
victor.rentea@gmail.com ♦ ♦ @victorrentea ♦ VictorRentea.ro
Are you Agile ?
Victor Rentea
Clean Code Evangelist
VictorRentea.ro/#playlist
best talks on:
Lead Architect
Internal Coach
Software Craftsman
Pair Programming, Refactoring, TDD
Java Champion
Founder
C#
VictorRentea.ro @victorrentea victor.rentea@gmail.com
Independent
Technical Trainer & Coach
HibernateSpring Java 8
Architecture, DDDDesign Patterns
Clean Code Unit Testing, TDD
Java Performance more…Scala
240+ days1500 devs6 years
VictorRentea.rovictor.rentea@gmail.com
30 companies
Posting daily on
+Live-Trainingon
30K 3K 2K
13 VictorRentea.ro
▪Arrange: setup the test fixture
▪Act: call the production code
▪Assert the outcomes
▪Annihilate[opt]: clean up
Terms
14 VictorRentea.ro
Why do we
Write Tests ?
16 VictorRentea.ro
To Read-the-Spec™
(before we finish the implem☺)
FEAR
Executable
Specification
always up-to-date
Why do we Write Tests ?
17 VictorRentea.ro
Medical Screening
18 VictorRentea.ro
Sensitive
Specific
Fast
Few
Clinical Tests
19 VictorRentea.ro
Sensitive
High Coverage %
Correct Tests
Specific
Expressive
Isolated & Robust
Low overlap
Fast
Few
Small, DRY tests
Test Design Goals
= Maintainable
fail for any bug
precise failures
20 VictorRentea.ro
Test code >> Prod code
Not Maintainable?
Under pressure, developers will:
@Ignore
delete test
// comment test
// @Test
delete asserts
invert asserts
EVIL
21 VictorRentea.ro
22 VictorRentea.ro
▪Code that you fear 😱
▪A distant corner in the logic
▪A bug (before fixing it) 🏆
▪for/if/while ⚙
▪Thrown exception
▪A method that just calls two others
▪Trivial code
▪Legacy code with 0 bugs, 0 changes
(over the last year)
Testing Priorities
PRIORITY
a.setName(b.getName());
*in case you're not 100% TDD
hard to understand
takes 3 mins of UI clicks to reproduce
+0.01%
23 VictorRentea.ro
Cost of Unit Tests
Cost
Coverage%
100%80% 90%60%
tradeoff
ROI=?
24 VictorRentea.ro
What do you do when you find a bug?
Takes guts to stop and think: “WHY?”
Then Unit Test.
You run to cover it.
25 VictorRentea.ro
Tests are green.
You implement a huge Change Request.
Tests are green.
Evergreen Tests
We ❤ Green Tests!
26 VictorRentea.ro
Evergreen Tests
27 VictorRentea.ro
Evergreen Tests
Coverage% = ?
28 VictorRentea.ro
Can you
TrustSuch Tests?
29 VictorRentea.ro
How can you check
that a test really covers
what it claims?
32 VictorRentea.ro
Mutation Testing
You break the
Production code
You get a "mutant" code
The tests should squash
the mutant by turning red
You run the Tests You undo the change
There are frameworks that play like this with your code,
but their results might be depressing
Tests fail ֞ Production code is altered
How can you check
that a test really covers
what it claims?
33 VictorRentea.ro
Always see your test failing
at least once
Tests, like laws, are meant to be broken
34 VictorRentea.ro
▪Regression Bug
- Yeehaaa! ➔ fix it
▪Deep Change Request
- Double Check ➔ Update/Delete the test?
▪Iso-functional changes
- Superficial API Changes ➔ adjust the test
- Refactoring internals ➔ test is too tightly coupled
▪A Bug in a Test
- Usually discovered via debugging
Why can a Test Fail ?
the usual suspect = production code
https://www.monkeyuser.com/
35 VictorRentea.ro
A Bug in a Test
36 VictorRentea.ro
A Bug in a Test
37 VictorRentea.ro
38 VictorRentea.ro
You want
Simple Tests !
Explicit
39 VictorRentea.ro
SimpleTests!
A bit of logic in a test
assertEquals("Greetings" + name, logic.getGreetings(name));
it's missing a " "!
Why? The same Dev wrote both prod and test code! ☺ CPP
➔ Prefer literals 
assertEquals("Greetings John", logic.getGreetings("John"));
Can you find the bug?
45 VictorRentea.ro
for loop
Testing a set of input-output pairs?
➔ Parameterized Unit Tests 
➔ .feature files 
WHY?!
SimpleTests!
47 VictorRentea.ro
Can be signed directly by Biz guys !
.feature files
48 VictorRentea.ro
49 VictorRentea.ro
Bridge the Gap
53 VictorRentea.ro
random
Testing to find errors?
➔ replay real calls from production 
(Even more: Golden Master Technique)
SimpleTests!
https://adrianbolboaca.ro/2014/05/golden-master/
54 VictorRentea.ro
callProd(…)
dependencies
TimeMachine.setTestTime(time);
actual = callProd(…);
assertEquals(new Date(), actual);
assertEquals(time, actual);
TimeMachine.clearTestTime(); // *
fails/passes randomly!
return TimeMachine.now();
return new Date();
return LocalDateTime.now();
+1ms?
asserting time
your custom class
Let's truncate! :D
draconian PowerMock?
* See here my auto-cleaning JUnit4 Time @Rule
,now
55 VictorRentea.ro
Tests Can
Control the Time
58 VictorRentea.ro
databases
files
queues
external web services
These are Integration Tests
SimpleTests!
59 VictorRentea.ro
GREEN
ZONE
Integration vs Unit Tests
Deep Testing
through many layers
Fragile
(depends on DB, files, other systems)
Such a failed test ⇒ a bug
Super-Fast
100 tests/sec
(some can be slower)
Slow
starts-up
the container
In-mem DB
62 VictorRentea.ro
Sensitive
High Coverage %
Correct Tests
Specific
Expressive
Isolated & Robust
Low overlap
Fast
Few
Small, DRY tests
Test Design Goals
63 VictorRentea.ro
Minimize Duplication
public void myTestRaw() {
Order o = new Order();
o.setDate(new Date());
o.setLines(new ArrayList<OrderLine>());
OrderLine ol1 = new OrderLine();
ol1.setProduct("P1");
ol1.setItems(3);
o.getLines().add(ol1);
OrderLine ol2 = new OrderLine();
ol2.setProduct("P2");
ol2.setItems(null);
o.getLines().add(ol2);
target.process(o);
}
Data Initialization
64 VictorRentea.ro
Fluent Builder Pattern
68 VictorRentea.ro
public void myTestWithBuildersAndObjectMother() {
Order o = anOrderWithOneLine()
.with(anOrderLine().withItem(anItem()))
.build();
target.process(o);
} Object Mother®
Fluent Builder®
Any use of ® in my talks is anecdotal
69 VictorRentea.ro
▪Fluent Builder®
▪Factory methods
- Object Mother shared between tests ?
▪Wrap production API
- In a more testable DSL
▪Keep common stuff in fields
▪Shared @Before
DRY Tests
Safe
Each @Test runs on a
fresh instance of the Test class
All use of ® in my talks is anecdotal
71 VictorRentea.ro
You want to shrink a large test
Abusing @Before
==Practical Guide☺==
Other tests do the same:
Time passes by
When you read a test:
▪ Arrange = method + @Before
▪ What part of it ?
You move some code in the @Before
▪ Mocks▪ Data Init ▪ Infra setup: DB, ..
72 VictorRentea.ro
SingleTestClass ATest
BTest
Fixture-Based Test Breakdown
@Before
Nested Test Fixtures in JUnit5: https://junit.org/junit5/docs/current/user-guide/#writing-tests-nested
@Test
@Test
@Test
sharedA
@Test
@Test
@Test
@Test
@Test
@Before
@Test
@Test
@Test
@Test
@Test
@Test
@Test
@Test
@Before
sharedB
73 VictorRentea.ro
Start with one Test class/Prod class
- If it grows (>300 lines?) or
- If many tests share a fixture
Split it
RecordRepositoryTest
RecordRepositorySearchForVersionTest
Maybe also split
the prod code ?
1DESIGN INSIGHT
74 VictorRentea.ro
5-10 lines
Descriptive names
Test Methods
public void givenAnInactiveCustomer_whenHePlacesAnOrder_itIsActivated()
public void getRecordDeltasForVersionWithDeletedRecord()
public void givenAProgramLinkedTo2Records_whenUpdated_2AuditsAreInserted()
RecordRowValidatorTest.invalidRecordStartDateFormat()
75 VictorRentea.ro
AnInactiveCustomerShould
.beActivatedWhenHePlacesAnOrder()
Another Naming Convention
"Given" = the class name
~ @Before
Fluent
"Then" part
(the expectations)
https://codurance.com/2014/12/13/naming-test-classes-and-methods/
76 VictorRentea.ro
Expressive Tests
Superb Failures
77 VictorRentea.ro
Suggestive Literals
@Test
public void customerEmailIsUpdated() {
Long customerId = createCustomer(new Customer("oldPhone"));
updateCustomerPhone(customerId, "newPhone");
Customer updatedCustomer = getCustomer(customerId);
assertEquals("newPhone", updatedCustomer.getPhone());
}
78 VictorRentea.ro
Assert a collection
Expressive Failures
(example)
assertEquals(1, names.size());
assertEquals("name", names.iterator().next());
assertEquals(Collections.singleton("name"), names);
vs
79 VictorRentea.ro
Assertions.*
assertThat(list).containsExactlyInAnyOrder(1,2,3);
assertThat(list).anyMatch(e -> e.getX() == 1);
assertThat(score).isEqualTo("Game won")
81 VictorRentea.ro
Sensitive
High Coverage %
Correct Tests
Specific
Expressive
Isolated & Robust
Low overlap
Fast
Few
Small, DRY tests
Test Design Goals
82 VictorRentea.ro
Should Tests Respect
Encapsulation?
83 VictorRentea.ro
FreshCodeLegacyCode
Encapsulated
Garbage
Covering Legacy
Code With Tests
vs
ShouldTestsRespect
Encapsulation?
YES
Test through the public API
Tests won't break when implementation changes
Practices the API
NO
Breaking encapsulation
is a key technique
Temporarily use package/public protection
84 VictorRentea.ro
Encapsulated
Garbage
Covering Legacy
Code With Tests
vs
85 VictorRentea.ro
You run your test suite
Test #13 is RED
To debug it, you run that test:
Test #13 goes GREEN
??!!!?!
Yet Another Happy Day#2…
86 VictorRentea.ro
You run your test suite
It’s all GREEN
You add Test #43
Test #13 turns RED
(untouched!)
You delete Test #43
Test #13 goes back GREEN
Yet Another Happy Day#3…
??!!!?!
87 VictorRentea.ro
@Before
▪In-memory Objects
▪COMMITs to a DB
▪External files/systems
Hidden Test Dependencies
- Static fields, singletons
- PowerMocks
- Thread Locals
- Container shared by tests [Spring]
- In-memory
- External (real)
Reset them in @After
➔ @DirtiesContext
➔ Isolated tests ran in Tx rolled back after the test
Intermediate
Commits
88 VictorRentea.ro
JUnit runs tests in unexpected order
To Ensure Independency
(DON'T DO THIS)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
Surprise me!
91 VictorRentea.ro
▪Test Design Principles
▪TDD
▪Mocks
▪Databases
▪Legacy Code
Agenda
92 VictorRentea.ro
A discipline
in which you grow software
in small increments
for which you write
the tests before the implementation
Test-Driven Development
Credited to Kent Beck, 2003
93 VictorRentea.ro
1. Write prod code only to fix a failing test
- Although we often foresee the implementation
2. Write 1 test for a feature not yet implemented
- It must fail with grace
3. Write just enough prod code
to pass the test
The 3 Rules of TDD--Uncle Bob
Code Golf
Fewest keystrokes
to make it pass
few
94 VictorRentea.ro
Red-Green-Refactor
With Grace
fail
KISS, YAGNI, Golf:
Write as little prod code,
don’t mind about quality
You can't break anything
•Start with the simplest cases
•Start with the ☺ flows
If you get stuck or
other tests break
=> revert and retry
DRY, Clean Code
Write prod code to
Make It Pass
Write a Failing Test
for a new feature
Refactor
prod XOR tests
pass
fail
Run
Tests
Run
Tests
Run
Tests
1-10 min
Incorrect? –
Overlapping? –
(could keep for documenting)
95 VictorRentea.ro
Rules of Simple Design
https://martinfowler.com/bliki/BeckDesignRules.html
2. Reveals Intention
3. No Duplication
4. Fewest Elements
1. Passes the Tests
96 VictorRentea.ro
TDD Schools of Thought
TDDasifyoumeantit
A comparative example:
Uncle Bob (Chicago School) vs Sandro Mancuso (London School): git has two branches.
https://gist.github.com/xpepper/2e3519d2cb8568a0b13739d9ae497f21
aka Chicago school aka London school
101 VictorRentea.ro
Invest any effort necessary to
create Unit Tests
for any tough problem you face
One of the best way
tests save you time!
102 VictorRentea.ro
Test-Driven Development
Design
Testable Design ?
https://martinfowler.com/articles/is-tdd-dead/
¿ messy thoroughly unit-tested code ?
∄
105 VictorRentea.ro
Should we TDD Everything ?
NO - Martin Fowler
https://martinfowler.com/articles/is-tdd-dead/
106 VictorRentea.ro
▪Test Design Principles
▪TDD
▪Mocks
▪Databases
▪Legacy Code
Agenda
107 VictorRentea.ro
108 VictorRentea.ro
Fake Objects
Fast
DB ☺
Repeatable
Isolation from external systems
Mentally Simpler
To test a layer, fake the layer bellow:
WHY?!
Cheating?
James Coplien: https://rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf
109 VictorRentea.ro
110 VictorRentea.ro
Fake
Mock
Verify a method call
verify(repo).save(…);
Stub
Respond to method calls
when(mock.method())
.thenReturn(…);
112 VictorRentea.ro
113 VictorRentea.ro
Side-effects
1) On external systems:
2) On in-memory objects
➔ assert their state after
What can a Unit Test check?
Input OutputFeature
(prod function)
Data from
dependencies
Input+Deps → Output
(real or stubbed)
a) Real: SELECT
b) Mocked: verify repo.save() was called
Input → Output
Simple and Elegant Tests
Pure Function: 𝑓 𝑥 = 𝑥2
Simplify design:
purify logic
Philosophic Slide
“Interaction Testing”
114 VictorRentea.ro
Extract Method
mock
stub
115 VictorRentea.ro
= Pure Function
visibility=? parameter count++
116 VictorRentea.ro
Free the Mocks!
Mock-free Tests!
117 VictorRentea.ro
The Circle of Purity
Professional Unit Testing – Mocking
118 VictorRentea.ro
infrastructure
domain
side effects
pure logic
2
134 VictorRentea.ro
It may be wiser to build
a testing infrastructure (DSL)
On the medium-long term
Than Mocking It:
150 VictorRentea.ro
▪Test Design Principles
▪TDD
▪Mocks
▪Databases
▪Legacy Code
Agenda
151 VictorRentea.ro
Legacy and Inheritance
Developers are the only persons on Earth

about
152 VictorRentea.ro
Goal: Survive
The First 3 Unit Tests
Test no.
difficulty
Writing Tests on Old Code
153 VictorRentea.ro
Testing Legacy Code: Feeling
https://www.youtube.com/watch?v=_gQ84-vWNGU
156 VictorRentea.ro
157 VictorRentea.ro157
158 VictorRentea.ro158
159 VictorRentea.ro159
160 VictorRentea.ro
163 VictorRentea.ro
▪Extract-'n-test
- Then mock it out
▪IDE Refactoring
- When not guarded by tests; mob refactoring
▪Frequent Commits
▪Break encapsulation
- Expose internal state
- Spy internal methods
▪Hack statics
- PowerMock methods (still, avoid…)
- Control global state
▪Copy, don’t Cut
- Make old code useless while still compiling
▪Look for Seams
- Decoupling places
▪Exploratory refactoring
- 30 mins that you always throw away at the end
- Seek how to make the design testable
▪Temporary ugly tests
▪Unit Test + Refactoring
- Go together
Legacy Testing Techniques
More on: http://blog.adrianbolboaca.ro/2015/02/unit-testing-on-legacy-code/
The one slide with
164 VictorRentea.ro
167 VictorRentea.ro
▪ Clean Code + Clean Coders Videos [CCEp#] http://www.cleancoders.com/
Robert C. Martin (Uncle Bob)
▪ (London-Style TDD): Growing Object-Oriented Software, Guided by Tests
Steve Freeman, Nat Pryce, 2009
▪ (Classic-Style TDD): Test-Driven Development, by example
Kent Beck, 2000
▪ The Art of Unit Testing
Roy Osherove, 2009
▪ Coding Dojo Handbook
Emily Bache, 2009
▪ https://springtestdbunit.github.io/spring-test-dbunit/faq.html
▪ Professional TDD with C#: Developing Real World Apps with TDD
James Bender, Jeff McWherter, 2011
▪ Agile in a Flash: https://pragprog.com/book/olag/agile-in-a-flash
▪ "Is TDD Dead?" - on You Tube
▪ Introducing BDD: http://dannorth.net/introducing-bdd/
Dan North
▪ Refactoring 2nd ed
Martin Fowler, 2018
Reading
168 VictorRentea.ro
▪Test where the Fear is
▪Correct Tests fail  Prod mutates
▪Explicit, Simple Tests
▪TODO: Try TDD!
▪Purify the heavy logic
▪Listen to Tests: Testable Design
Key Points
169 VictorRentea.ro
Why Should I
Write Tests ?
171 VictorRentea.ro171
¡¡ PLEASE !!
Hunt me down for questions!
172 VictorRentea.ro
Thank You!
VictorRentea.ro
Trainings, talks, goodies
@VictorRentea
Follow me for quality posts:
victorrentea.ro/community
Speaking Romanian? join me
A SCALABILITY PROBLEM:
OUT OF STICKERS
AND KEY CHEAT-SHEETS¡¡ PLEASE !!
Hunt me down for questions!
YOU CAN DOWNLOAD AND PRINT THEM
YOURSELF FROM VICTORRENTEA.RO

The Art of Unit Testing - Towards a Testable Design