mockist vs. classicists tdd
TRANSCRIPT
Classicists
● „old school“: Kent Beck, Uncle Bob, …
● state verification
● bottom-up/inside-out
● Avoid mocks when possible
Mockists
● „London School“: Steve Freeman, Nat Pryce
● XP 2000 „Endo-Testing: Unit Testing with
Mock Objects “
● OOPSLA 2004 „Mock Roles, not Objects“
● Book „Growing Object Oriented Software“
#GOOS 2009
Mockists
● ATDD
● Outside-In Design
● Hexagonal / Ports&Adapters Architecture ● also for classicists
● Mocking to isolate layers
● Interaction based testing ● „Back-door“
Architecture
● Mockist OO-style ● Message Passing/Event-Architecture
● Topology / Message flow
● „Tell don‘t ask“
● Classicist FP-style ● mutable objects encapsulating state
● pure functions & immutable value objects
● details: algorithms, logic, conditionals
Outside-In Design
UI
Domain Service
Repository DB Adapter
DB
Domain Service Interface
Unit Test
End2End Test
Outside-In Design
UI
Domain Service
Repository DB Adapter
DB
Repository Interface
Domain Service Interface
Unit Test
Unit Test
End2End Test
Outside-In Design
UI
Domain Service
Repository DB Adapter
DB
Repository Interface
Domain Service Interface
Unit Test
Unit Test
Integration
Test
End2End Test
Classicists Design
● Bottom-up ● emergent
● „TDD as if you meant it“ (YAGNI?)
● Middle ground? ● Acceptance tests => Domain
Classicist IO
out = pureFunction(in); object.changeStateBasedOn(in); out = object.getState();
● Functional
● State-based
Mockist IO: CQS
public Object myQuery() { return neighbour.query(); } when(neighbour.query()).thenReturn(in);
● Queries: Stubbing indirect input
Mockist IO: CQS
public Object myQuery() { return neighbour.query(); } when(neighbour.query()).thenReturn(in); private void myCommand() { neighbour.command(out); } verify(neighbour).command(out);
● Queries: Stubbing indirect input
● Commands: Spies check indirect output
Let‘s code!
● Content: Kata „Game of Life“ ● Phase 1: Outside-In Mockist style
● Mockless Classicist design
● Phase 2: refactor to mockless Classicist design
● Mode: Mob Programming ● 1 Driver
● N Navigators
● Variant: David = PO & facilitator
Classicist Isolation
● No isolation = „front door“ ● Leaf
● Integrated test
● By design ● Context independence: parameterize
methods/constructors, values/value objects,
intermediary results
● „Functional Core, Imperative Shell“
String renderMail(String mail) { String name = userRepo.nameFor(mail); return renderMailAndName(mail, name); } @Test public void renderMail() { when(userRepo.nameFor("[email protected]")) .thenReturn("Joe Customer"); assertEquals("[email protected] <Joe Customer>", mailService.renderMail("[email protected]")); }
Isolation via mocks
String renderMail(String mail) { String name = userRepo.nameFor(mail); return renderMailAndName(mail, name); } @Test public void renderMail() { when(userRepo.nameFor("[email protected]")) .thenReturn("Joe Customer"); assertEquals("[email protected] <Joe Customer>", mailService.renderMail("[email protected]")); } @Test public void renderMail() { assertEquals("[email protected] <Joe Customer>", mailService.renderMailAndName("[email protected]", "Joe Customer")); }
Mockless isolation
Lizenz
Creative Commons Attribution-ShareAlike 3.0
https://creativecommons.org/licenses/by-sa/3.0/de/
TDD as if you meant it
1. Write exactly one failing test
2. Make the test pass by writing implementation code
in the test method
3. When duplication is spotted extract the
implementation from tests to:
1. a new method in the test class
2. an existing method in the test class
4. When more methods belong together extract them
into a new class
5. Refactor as required
by Adi Bolboaca