Weitere ähnliche Inhalte Ähnlich wie Don't Be Mocked by your Mocks - Best Practices using Mocks (20) Mehr von Victor Rentea (20) Kürzlich hochgeladen (20) Don't Be Mocked by your Mocks - Best Practices using Mocks1. 145 © VictorRentea.ro
a training by
Don't be Mocked by your Mocks
victorrentea@gmail.com victorrentea.ro @victorrentea
3. Victor Rentea
Blog, Talks, Goodies:
VictorRentea.ro
Independent Trainer & Consultant
Founder of
Bucharest Software Craftsmanship Community
Java Champion
❤️ Simple Design, Refactoring, Unit Testing ❤️
4. Technical Training
HibernateSpring Functional Prog
400 days
(100+ online)2000 devs8 years
Training for you or your company: VictorRentea.ro
40 companies
Follow me:
35K 4K 3K
Java PerformanceReactive
Design Patterns Refactoring Unit Testing
any
lang
uage
6. 150 © VictorRentea.ro
a training by
Decouple a Dependency in Tests
Isolated
versus external systems
Fast
DB, APIs
Test Less Code
Test a layer, by faking the layer below:
WHY?!
Cheating?
layers
10. 154 © VictorRentea.ro
a training by
Mock
Verify a method call
verify(repo).save(…);
Stub
Respond to method calls
when(mock.method())
.thenReturn(…);
Dummy
Avoids Null Pointers
Mock w/o behavior
system.setAuthorizer(new NoopAuthorizer());
https://blog.cleancoder.com/uncle-bob/2014/05/14/TheLittleMocker.html
Fake
Alternative
implementationTest Double
11. 155 © VictorRentea.ro
a training by
Fake
Alternative
implementation
Test Implementation
(eg. storing in a hash map)
when(userRepo.findById(1L))
.thenReturn(u);
// prodCall()
userRepo.save(u); //id=1
// prodCall()
Vs
C# Repository pattern + LINQ queries.
Given you trust LINQ, can be tested with just an in-memory list.
TIP: Consider
if copy-pasting
stubbing
when(...)
.thenAnswer(<callback>);
.. or instead of
dynamic stubs
verify(orderRepo).save(...);
list= orderRepo.findAll();
assert list contains new order
12. 156 © VictorRentea.ro
a training by
Mock
Verify a method call
verify(repo).save(…);
Stub
Respond to method calls
when(mock.method())
.thenReturn(…);
Dummy
Avoids Null Pointers
= Mock w/o behavior
system.setAuthorizer(new NoopAuthorizer());
Fake
Alternative
implementationTest Double
you stub or mock a method
13. 157 © VictorRentea.ro
a training by
Mocks aren't Stubs
https://martinfowler.com/articles/mocksArentStubs.html
Stub Queries, Expect Actions
orderRepo.save(Order)userRepo.findById(id):User
Verify what tested code does
based on user's state
when(repo.findById(…)).thenReturn(user);
out = testedCode();
verify(repo).findById(…);
Since Mockito 2.x stubbed methods are automatically verified by default
2
Command-Query Separation Principle
Need Both?
14. 158 © VictorRentea.ro
a training by
No side effects
No INSERTs, POSTs, queues, files, fields,…
𝑒𝑔. 𝑀𝑎𝑡ℎ𝑒𝑚𝑎𝑡𝑖𝑐𝑎𝑙 𝐹𝑢𝑛𝑐𝑡𝑖𝑜𝑛𝑠: 𝑓 𝑥, 𝑦 = 𝑥2
+ 𝑦
(logging doesn't count)
Referential Transparent
Same arguments ➔ same result
No current time, random, GET, SELECT…
Pure Functions
17. 161 © VictorRentea.ro
a training by
Side-effects
1) On external systems:
2) On in-memory objects
➔ assert their state after
What can a Unit Test check?
OutputInput Params Feature
(method)
Data from
dependencies
Input+Deps → Output
a) Real: SELECT from test to check the INSERT
b) Mocked: verify repo.save() was called
Input → Output
Pass More IN
Philosophic Slide
aka Interaction Testing
Return Change
Pure Function: 𝑓 𝑥 = 𝑥2
The Simplest Tests
a) Real: SELECT
b) Stub: when.thenReturn.
18. 163 © VictorRentea.ro
a training by
Extract Method
mock
verify(orderRepo).save(…);
stub
when(userRepo.findById()).thenReturn(…);
No mocks
Stubs & Mocks
ArgumentCaptor
SimplerTests
Test This:
x 8 tests
21. 166 © VictorRentea.ro
a training by
infrastructure
domainfunctional core
3
The Universal Architecture
Side-effects &
Dependencies
Code Dependency
aka Onion
aka Hexagonal
aka Ports-and-Adapters
25. 170 © VictorRentea.ro
a training by
NPE
How to test this one ?
Test OverlapHeavy Tests
YES
Complex
Logic+
NO
(Partial Mock)
YES
Few?
(eg. NPE)
Should other tests also execute createOrder() ?
many
27. 172 © VictorRentea.ro
a training by
Partial Mock
Mocked Methods
createOrder
Tested Methods
placeOrder
Same Object
28. 173 © VictorRentea.ro
a training by
Missed Design Hint
NPE
Tests
How to test this one ?
Test OverlapHeavy Tests
YES NO
(Partial Mock)
Complex
Logic
Should other tests also execute createOrder() ?
OrderFactory
NO
(Extract to New Class)
Separation By Layers of Abstraction
Complex
Logic
@Mock
many
4
29. 186 © VictorRentea.ro
a training by
What's so bad about them after all ?
But I ❤️ Mocks!
I use them everywhere!
Fragile Tests Inconsistent Tests Incorrect Tests
31. 188 © VictorRentea.ro
a training by
You have to do a difficult change.
First, you make that change easy (this might be difficult).
Then, you do the easy change.
-- Kent Beck
Changing Existing Code
Preparatory Refactoring
The Need for Refactoring
Production Code
33. 190 © VictorRentea.ro
a training by
Which is
easier to write?
MockEverything
LessMocks
(w/o functional change requests)
Which is stabler?
A
B
C D
Bdirect dependency
(mock) Dfinal real system
(SELECT)
(mock)
Ctest A+B
together
TEST
At which API to verify?Easier to Write Reliable & Stable
Mocks "Freeze" APIs
eg. Repo
Closer to Spec
B1
B2
Are these Unit Tests?
(all are fresh classes)
34. 191 © VictorRentea.ro
a training by
Unit Testing
What’s a Unit?
It's a unit of behavior
= the smallest part of a feature that you can test in isolation
a method ?
a class ?
a full use-case?
- Kent Beck, inventor of TDD, XP, Unit Testing
It's perfectly fine for unit tests to talk to databases and filesystems! – talk
... as long as your tests are isolated ➔ in-memory DB; Docker
36. 193 © VictorRentea.ro
a training by
Don't Mock between newly-created classes
vs Stable Interfaces
✓Standard API
(lib, framework, "platform")
✓Multiple implems
✓Old API
Actually, there's an entire TDD style relying
on mocking not-yet-implemented classes
38. 195 © VictorRentea.ro
a training by
A
B
TEST
Kept in Sync
Inconsistencies
when(b.f(7)).thenReturn(1)
assertEquals(1, b.f(7));
Impossible Test Cases
assertEquals(-1, b.f(null));
b.f(x * 2);Production code:
assertEquals(2, b.f(7));
You test them
separately
43. 200 © VictorRentea.ro
a training by
Test requirements, not implementation details!
James Coplien: https://rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf
44. 201 © VictorRentea.ro
a training by
Fragile Tests
(when design changes)
Inconsistencies
(when requirements change)
Incorrect Tests
(when testing in isolation)
Extensive Mocking
45. 202 © VictorRentea.ro
a training by
Test more classes together!
(versus mocking every dependency of the tested class)
46. 205 © VictorRentea.ro
a training by
Large Input Data
Many Tests
A
B
C D
final real system
(SELECT)
TEST
eg. Repo
Testing
Framework
(testing DSL)
GET
Blackbox
Test
verify via
another API call
Build Deeper Tests
Reliable & Stable
Closer to Spec
POST
As deep as you can to keep them
maintainable and reliable
47. 206 © VictorRentea.ro
a training by
A
B
C D
final real system
(SELECT)
TEST
eg. Repo
Testing
Framework
(testing DSL)
GET
Blackbox
Test
verify via
another API call
Build Deeper Tests
Reliable & Stable
Closer to Spec
POST
As deep as you can to keep them
understandable, reliable & fast
Large Input Data
Many Tests
48. 207 © VictorRentea.ro
a training by
It may be cheaper to build
a testing framework
On the medium-long term
test it end-to-end
Like Uncle Bob did (2018)
than mocking the little parts
and
49. 208 © VictorRentea.ro
a training by
is impossible for some use-cases
(exponential number of execution paths)
Decompose Complex Flows in Components
tested independently
But to test it end-to-end
Mocks are Inevitable
51. 210 © VictorRentea.ro
a training by
Mock Roles, Not Objects without a clear contract
http://jmock.org/oopsla2004.pdf
Challenge: 🥇
Try to extract an interface from the class you want to mock!
Redesign until that interface makes sense
6
52. 212 © VictorRentea.ro
a training by
A) Test More
STOP
and refactor testsA or prodB,C
How many mocks per @Test
Using MORE?
A
B
C
D
E F
(Including @Before and test super-classes)
High Coupling
C) Redesign Responsibilities8
= dependencies count
54. 214 © VictorRentea.ro
a training by
Hidden Dependencies
Static Library Calls
LocalDate.now();
new
new Date();
Encapsulate in mockable
instances passed in as
dependencies
private TimeProvider time;
System.currentTimeMillis();
55. 217 © VictorRentea.ro
a training by
Best if simple and pure
If you need to Mock it
It should not be an Util!
no polymorphism (proxies, strategy...), global state, no lifecycle management, uncontrolled usage
56. 219 © VictorRentea.ro
a training by
Mocks returning Mocks
Mock data objects (Entities, Value Objects, ...)
Too many mocks
Partial Mocks
Mock Statics
Verify stubbed methods
Check how many times() a call happened
Verify no extra call happen or never()
Capture and assert every argument
Populate Test Instances
Mocking Worst Practices
59. 222 © VictorRentea.ro
a training by
Then, What to mock?
Legacy Code
As an interim stage
Libraries or External Systems
Mock your adapters
Slow or Unreliable Resources
If impossible to run them in-memory / Dockerized
Well Defined Roles
Try to extract a well defined interface
WireMock?
64. 227 © VictorRentea.ro
a training by
Thank You!
VictorRentea.ro
Blog⭐, Company Training, Masterclasses, Best Talks,...
@VictorRenteavictorrentea@gmail.com
¡¡ PLEASE !!
Ask me questions!
Training Topics:
▪ Clean Code + Refactoring
▪ Design Patterns
▪ Unit Testing + TDD
▪ Advanced FP with Java
▪ Spring
▪ Hibernate/JPA
▪ Reactive Programming
▪ Java Performance
▪ Pragmatic DDD