Designing Testable Software
OpKoKo 16.2
Ekerö October 21, 2016
@DanielDeogun
@DanielDeogun
About Me
Daniel Deogun
Coder and Quality Defender
- VP Academy, Core 3, Stockholm
- Current assignment Hi3G / Nordic Choice Hotels
- Speaker, Teacher, Lead Developer
- Author of Secure by Design, Manning publ (in progress)
- Interests: DDD, DDSec, TDD, BDD, DbC, …
@DanielDeogun
Conclusion
- Put the test hat on when designing a system
- Testing is quite hard and require a lot of good design
- You get pretty far by thinking test first
@DanielDeogun
The Spec of the New “System”
Easy to add / remove / update
functionality
Have same functionality as
the “old” system
Must be resilient
Easy to maintain
@DanielDeogun
Where do you begin?
[1]
@DanielDeogun
Test Hat On
Let’s put the test hat on
and see what we need…
[2]
@DanielDeogun
Requirement
Have same functionality as
the “old” system
@DanielDeogun
Requirement
How do we verify this?
Have same functionality as
the “old” system
@DanielDeogun
Requirement
How do we verify this?
Is there any
documentation?
Have same functionality as
the “old” system
@DanielDeogun
Requirement
How do we verify this?
Is there any
documentation?
How do we report
progress?
Have same functionality as
the “old” system
@DanielDeogun
Requirement
How do we verify this?
Is there any
documentation?
Is there a domain expert?
How do we report
progress?
Have same functionality as
the “old” system
@DanielDeogun
Requirement
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
Have same functionality as
the “old” system
@DanielDeogun
Behavior Driven Development
in a Nutshell
BDD tries to capture the behavior of a system, not how it’s implemented
@DanielDeogun
BDD in Practice
Given …
When …
Then …
scenarios
produce
Gherkin notation
@DanielDeogun
BDD in Practice
Scenarios Act As a Client
Given …
When …
Then …
public class Scenario {
public void given() {…}
public void when() {…}
public void then() {…}
}
convert to
executable test acting as a client
invokes
application
@DanielDeogun
Application Behavior Captured
by Scenario Tests
BDD Scenarios
application
@DanielDeogun
Application Behavior Captured
by Scenario Tests
BDD Scenarios
But what about dependencies
to other systems?
invokes
application
@DanielDeogun
Application Behavior Captured
by Scenario Tests
BDD Scenarios
But what about dependencies
to other systems?
invokes
application
Let’s have a look at 3 important principles…
@DanielDeogun
Dependency Inversion
Principle (DIP)
High-level modules should not depend on low-level modules. Both
should depend on abstractions.
Abstractions should not depend on details. Details should depend
on abstractions.
- https://en.wikipedia.org/wiki/Dependency_inversion_principle
@DanielDeogun
Dependency Inversion
Principle (DIP)
Dependency
Dependency implementation
abstraction
@DanielDeogun
Dependency Injection (DI)
Explained
public class Monkey {
private final Banana banana;
public Monkey() {
this.banana = new Banana();
}
…
}
Monkey depends on Banana but the
Monkey creates the banana.
public class Monkey {
private final Banana banana;
public Monkey(final Banana banana) {
this.banana = notNull(banana);
}
…
}
Monkey depends on Banana but
banana is given (injected) to Monkey
@DanielDeogun
Liskov’s
Substitution Principle
Let ϕ(x) be a property provable about objects x of type T.
Then ϕ(y) should be true for objects y of type S where S is a subtype of T.
- Barbara Liskov and Jeannette Wing [3]
@DanielDeogun
LSP - “For Dummies”
If C is a subtype of P, then objects of type P may be replaced by objects of
type C without violating behavior or invariants
- Common Sense
class C extends P {…}
final P p = new C();
@DanielDeogun
The Beautiful Trinity
DIP + DI + LSP = True
[6]
@DanielDeogun
DIP, DI, and LSP
Allows Isolated Testing
Let’s use DI to inject dependencies
Let’s use DIP to remove dependencies to low
level implementations
Let’s use LSP to ensure invariants and
behavior
dependency
abstraction
@DanielDeogun
Pros & Cons
BDD & Spec by Example
+ Easy to verify business rules and expected behavior
+ A good way to learn how the system works
+ Creates confidence
- Deciding what to test may be hard
- Feature driven scenario organization may create duplicated tests
- Requires deep domain knowledge
@DanielDeogun
Evaluation
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
Have same functionality as
the “old” system
@DanielDeogun
Evaluation
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
√
Have same functionality as
the “old” system
@DanielDeogun
Evaluation
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
√
√?
Have same functionality as
the “old” system
@DanielDeogun
Evaluation
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
√
√
√?
Have same functionality as
the “old” system
@DanielDeogun
Evaluation
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
√
√?√
√?
Have same functionality as
the “old” system
@DanielDeogun
Evaluation
How do we verify this?
Is there any
documentation?
Is there a domain expert?
Do we want “exactly”
the same behavior?
How do we report
progress?
√
√
√
?√
√?
Have same functionality as
the “old” system
@DanielDeogun
Requirement
Easy to add / remove / update
functionality
Easy to maintain
@DanielDeogun
Requirement
Easy to add / remove / update
functionality
How do we avoid breaking things?
Easy to maintain
@DanielDeogun
Requirement
Easy to add / remove / update
functionality
How do we avoid breaking things?
How do we design for change?
Easy to maintain
@DanielDeogun
Requirement
Easy to add / remove / update
functionality
How do we avoid breaking things?
How do we design for change?
Easy to maintain
What does easy to maintain
mean?
@DanielDeogun
Test Driven Development
RED
GREEN
REFACTOR
Prove need
Smallest
code change
Improve
TDD tend to focus on how something is
implemented rather than its behavior
A good practice is to use BDD when doing TDD
@DanielDeogun
TDD Á la BDD
public void test_ticker() {
Ticker ticker = new Ticker();
ticker.increment();
assertEquals(1, ticker.value());
}
TDD
@DanielDeogun
TDD Á la BDD
public void test_ticker() {
Ticker ticker = new Ticker();
ticker.increment();
assertEquals(1, ticker.value());
}
TDD
public void should_increment_ticker() {
givenTickerWithRandomStart();
int expectedValue =
ticker.value() +
ticker.incrementStep();
ticker.increment();
thenTickerIsIncrementedTo(expectedValue);
}
TDD á la BDD
@DanielDeogun
TDD Á la BDD
public void test_ticker() {
Ticker ticker = new Ticker();
ticker.increment();
assertEquals(1, ticker.value());
}
!
- Never verify more than one behavior in each test
- Don’t use a common set up method
TDD
public void should_increment_ticker() {
givenTickerWithRandomStart();
int expectedValue =
ticker.value() +
ticker.incrementStep();
ticker.increment();
thenTickerIsIncrementedTo(expectedValue);
}
TDD á la BDD
@DanielDeogun
Mocks
“…mock objects are simulated objects that mimic the behavior of real
objects in controlled ways. A programmer typically creates a mock object to
test the behavior of some other object, …”
https://en.wikipedia.org/wiki/Mock_object
@DanielDeogun
Use DI to Inject Mocks
private final List<Item> items = mock(List.class);

private final ShoppingCart shoppingCart = new ShoppingCart(items);
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean add(final Item item) {

return items.add(notNull(item));

}



public boolean remove(final Item item) {

return items.remove(notNull(item));

}

…
@DanielDeogun
The Great Frustration
Incorrect mocking makes you spend more time updating test
code than production code
And the reason is…
@DanielDeogun
The Great Frustration
Incorrect mocking makes you spend more time updating test
code than production code
And the reason is…
Nobody puts Barbra in the corner!
@DanielDeogun
Violating LSP
Yield Brittle Tests
private final List<Item> items = mock(List.class);

private final ShoppingCart shoppingCart = new ShoppingCart(items);
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean add(final Item item) {

return items.add(notNull(item));

}



public boolean remove(final Item item) {

return items.remove(notNull(item));

}

…
@DanielDeogun
Violating LSP
Yield Brittle Tests
@Test

public void should_remove_item() {

final Item coke = new Coke();

BDDMockito.given(items.remove(coke)).willReturn(true);



final boolean result = shoppingCart.remove(coke);



assertTrue(result);

}
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean remove(final Item item) {
return items.remove(notNull(item));
}

…
@DanielDeogun
Violating LSP
Yield Brittle Tests
@Test

public void should_remove_item() {

final Item coke = new Coke();

BDDMockito.given(items.remove(coke)).willReturn(true);



final boolean result = shoppingCart.remove(coke);



assertTrue(result);

}
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean remove(final Item item) {
return items.remove(notNull(item));
}

…
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean remove(final Item item) {

return items.removeAll(items.stream()

.filter(i -> i.equals(item))

.collect(toList()));

}
@DanielDeogun
Violating LSP
Yield Brittle Tests
@Test

public void should_remove_item() {

final Item coke = new Coke();

BDDMockito.given(items.remove(coke)).willReturn(true);



final boolean result = shoppingCart.remove(coke);



assertTrue(result);

}
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean remove(final Item item) {
return items.remove(notNull(item));
}

…
public class ShoppingCart {

private final List<Item> items;



public ShoppingCart(final List<Item> items) {

this.items = notNull(items);

}



public boolean remove(final Item item) {

return items.removeAll(items.stream()

.filter(i -> i.equals(item))

.collect(toList()));

}
java.lang.NullPointerException
@DanielDeogun
Analysis
The “items” mock doesn’t satisfy LSP
Invoking an unmocked method on the items object causes a failure
Beware: Mockito uses default mocking behavior on some types
(e.g. List, int, boolean, etc)
private final List<Item> items = mock(List.class);

private final ShoppingCart shoppingCart = new ShoppingCart(items);
@DanielDeogun
Tip of the Day
Make domain classes final to “prevent“ mocking!
[8]
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class se.omegapoint.opkoko.MyDomainClass
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
@DanielDeogun
Branch By Code
Using Feature Toggles
http://martinfowler.com/articles/feature-toggles.html
@DanielDeogun
Branch By Code
Using Feature Toggles
Release toggles
• Compile time dependency
• Ex: use DI and start app with different configuration
Ops toggles
• Runtime dependency
• Ex: special API only available for operations
Experiment toggles
• Runtime dependency used for A/B testing
• Ex: toggle is based on user information
Permission toggles
• Runtime dependency
• Ex: Toggle is based on payment information
@DanielDeogun
How Do Feature Toggles
Affect Testing?
Release toggles
• test what’s enabled (in production)
Ops toggles
• make sure they only work for operations
Experiment toggles
• test the selection algorithm
Permission toggles
• test applicability
We cannot test every possible combination
Make an educated choice
@DanielDeogun
Evaluation
Easy to add / remove / update
functionality
How do we avoid breaking things?
How do we design for change?
Easy to maintain
What does easy to maintain
mean?
@DanielDeogun
Evaluation
Easy to add / remove / update
functionality
How do we avoid breaking things?
How do we design for change?
Easy to maintain
What does easy to maintain
mean?
√
@DanielDeogun
Evaluation
Easy to add / remove / update
functionality
How do we avoid breaking things?
How do we design for change?
Easy to maintain
What does easy to maintain
mean?
√
√
@DanielDeogun
Evaluation
Easy to add / remove / update
functionality
How do we avoid breaking things?
How do we design for change?
Easy to maintain
What does easy to maintain
mean?
√√?
√
@DanielDeogun
Requirement
Must be resilient
@DanielDeogun
Requirement
How do we measure “resilience?”
Must be resilient
@DanielDeogun
Requirement
How do we measure “resilience?”
How do we test resilience?
Must be resilient
@DanielDeogun
Requirement
How do we measure “resilience?”
How do we test resilience?
Can we find the “upper bound?”
Must be resilient
@DanielDeogun
System Integration Resilience
@DanielDeogun
Circuit Breaker
“A circuit breaker is an automatically operated electrical switch designed
to protect an electrical circuit from damage caused by overcurrent or
overload or short circuit.”
- https://en.wikipedia.org/wiki/Circuit_breaker
@DanielDeogun
Circuit Breakers
Avoid Killing Backend
circuit breakers
@DanielDeogun
Schematic view of a
Circuit Breaker
- Release It! Michael Nygard, The Pragmatic Bookshelf
@DanielDeogun
Bulkhead Pattern
https://github.com/Netflix/Hystrix/wiki/How-it-Works#Threads
[9]
@DanielDeogun
Separate Thread Pools
Avoid Cascading Failures
circuit breakers
Separate thread pools
@DanielDeogun
Request Collapsing Pattern
https://github.com/Netflix/Hystrix/wiki/How-it-Works#RequestCollapsing
@DanielDeogun
“Internal” Resilience
[5]
Bad input data
Corrupt responses
Design by Contract
Message driven
Domain Driven Design
Null values
Default values
Immutability
Concurrency
@DanielDeogun
Hostile Environment
Imagine an environment whose only purpose is to
bring your application to its knees
Each endpoint is a potential “threat”
Put your application under heavy load, inject bad
input, return corrupt data, etc
Make this a stage in your delivery pipeline
Monitor memory consumption, response times, etc
@DanielDeogun
Evaluation
How do we measure “resilience?”
How do we test resilience?
Must be resilient
Can we find the “upper bound?”
@DanielDeogun
Evaluation
How do we measure “resilience?”
How do we test resilience?
Must be resilient
Can we find the “upper bound?”
√?
@DanielDeogun
Evaluation
How do we measure “resilience?”
How do we test resilience?
Must be resilient
√
Can we find the “upper bound?”
√?
@DanielDeogun
Evaluation
How do we measure “resilience?”
How do we test resilience?
Must be resilient
√
√
Can we find the “upper bound?”
√?
@DanielDeogun
The Spec of the New “System”
Easy to add / remove / update
functionality
Have same functionality as
the “old” system
Must be resilient
Easy to maintain
@DanielDeogun
Conclusion
- Put the test hat on when designing a system
- Testing is quite hard and require a lot of good design
- You get pretty far by thinking test first
@DanielDeogun
Q & A
[7]
@DanielDeogun
Thanks
@DanielDeogun
@DanielDeogun
References
[1] Torsten, math teacher, https://flic.kr/p/ndFN4Q License: https://creativecommons.org/licenses/by/2.0/
[2] Emily Moe, IMG_7788, https://flic.kr/p/aH4rwk, License: https://creativecommons.org/licenses/by-nd/2.0/
[3] Liskov’s Substitution Principle, Wikipedia, https://en.wikipedia.org/wiki/Liskov_substitution_principle
[4] Tsutomu Takasu, Horse racing event, https://flic.kr/p/6Yy3NZ, License: https://creativecommons.org/licenses/by/2.0/
[5] http://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Emblem-evil-computer.svg/500px-Emblem-evil-computer.svg.png
[6] Huey, Dewey, and Louie Duck, drawn by cartoonist Carl Barks, https://en.wikipedia.org/wiki/File:Louie_Dewey_and_Huey.png
[7] Questions, https://flic.kr/p/9ksxQa] by Damián Navas, License: https://creativecommons.org/licenses/by-nc-nd/2.0/
[8] Chuck Coker, Light Bulb No. 1, https://flic.kr/p/66KLFn, License: https://creativecommons.org/licenses/by-nd/2.0/
[9] DRVMX, Titantic, https://flic.kr/p/gNLK84, License: https://creativecommons.org/licenses/by-nd/2.0/

Designing Testable Software

  • 1.
    Designing Testable Software OpKoKo16.2 Ekerö October 21, 2016 @DanielDeogun
  • 2.
    @DanielDeogun About Me Daniel Deogun Coderand Quality Defender - VP Academy, Core 3, Stockholm - Current assignment Hi3G / Nordic Choice Hotels - Speaker, Teacher, Lead Developer - Author of Secure by Design, Manning publ (in progress) - Interests: DDD, DDSec, TDD, BDD, DbC, …
  • 3.
    @DanielDeogun Conclusion - Put thetest hat on when designing a system - Testing is quite hard and require a lot of good design - You get pretty far by thinking test first
  • 4.
    @DanielDeogun The Spec ofthe New “System” Easy to add / remove / update functionality Have same functionality as the “old” system Must be resilient Easy to maintain
  • 5.
  • 6.
    @DanielDeogun Test Hat On Let’sput the test hat on and see what we need… [2]
  • 7.
  • 8.
    @DanielDeogun Requirement How do weverify this? Have same functionality as the “old” system
  • 9.
    @DanielDeogun Requirement How do weverify this? Is there any documentation? Have same functionality as the “old” system
  • 10.
    @DanielDeogun Requirement How do weverify this? Is there any documentation? How do we report progress? Have same functionality as the “old” system
  • 11.
    @DanielDeogun Requirement How do weverify this? Is there any documentation? Is there a domain expert? How do we report progress? Have same functionality as the “old” system
  • 12.
    @DanielDeogun Requirement How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? Have same functionality as the “old” system
  • 13.
    @DanielDeogun Behavior Driven Development ina Nutshell BDD tries to capture the behavior of a system, not how it’s implemented
  • 14.
    @DanielDeogun BDD in Practice Given… When … Then … scenarios produce Gherkin notation
  • 15.
    @DanielDeogun BDD in Practice ScenariosAct As a Client Given … When … Then … public class Scenario { public void given() {…} public void when() {…} public void then() {…} } convert to executable test acting as a client invokes application
  • 16.
    @DanielDeogun Application Behavior Captured byScenario Tests BDD Scenarios application
  • 17.
    @DanielDeogun Application Behavior Captured byScenario Tests BDD Scenarios But what about dependencies to other systems? invokes application
  • 18.
    @DanielDeogun Application Behavior Captured byScenario Tests BDD Scenarios But what about dependencies to other systems? invokes application Let’s have a look at 3 important principles…
  • 19.
    @DanielDeogun Dependency Inversion Principle (DIP) High-levelmodules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. - https://en.wikipedia.org/wiki/Dependency_inversion_principle
  • 20.
  • 21.
    @DanielDeogun Dependency Injection (DI) Explained publicclass Monkey { private final Banana banana; public Monkey() { this.banana = new Banana(); } … } Monkey depends on Banana but the Monkey creates the banana. public class Monkey { private final Banana banana; public Monkey(final Banana banana) { this.banana = notNull(banana); } … } Monkey depends on Banana but banana is given (injected) to Monkey
  • 22.
    @DanielDeogun Liskov’s Substitution Principle Let ϕ(x)be a property provable about objects x of type T. Then ϕ(y) should be true for objects y of type S where S is a subtype of T. - Barbara Liskov and Jeannette Wing [3]
  • 23.
    @DanielDeogun LSP - “ForDummies” If C is a subtype of P, then objects of type P may be replaced by objects of type C without violating behavior or invariants - Common Sense class C extends P {…} final P p = new C();
  • 24.
  • 25.
    @DanielDeogun DIP, DI, andLSP Allows Isolated Testing Let’s use DI to inject dependencies Let’s use DIP to remove dependencies to low level implementations Let’s use LSP to ensure invariants and behavior dependency abstraction
  • 26.
    @DanielDeogun Pros & Cons BDD& Spec by Example + Easy to verify business rules and expected behavior + A good way to learn how the system works + Creates confidence - Deciding what to test may be hard - Feature driven scenario organization may create duplicated tests - Requires deep domain knowledge
  • 27.
    @DanielDeogun Evaluation How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? Have same functionality as the “old” system
  • 28.
    @DanielDeogun Evaluation How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? √ Have same functionality as the “old” system
  • 29.
    @DanielDeogun Evaluation How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? √ √? Have same functionality as the “old” system
  • 30.
    @DanielDeogun Evaluation How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? √ √ √? Have same functionality as the “old” system
  • 31.
    @DanielDeogun Evaluation How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? √ √?√ √? Have same functionality as the “old” system
  • 32.
    @DanielDeogun Evaluation How do weverify this? Is there any documentation? Is there a domain expert? Do we want “exactly” the same behavior? How do we report progress? √ √ √ ?√ √? Have same functionality as the “old” system
  • 33.
    @DanielDeogun Requirement Easy to add/ remove / update functionality Easy to maintain
  • 34.
    @DanielDeogun Requirement Easy to add/ remove / update functionality How do we avoid breaking things? Easy to maintain
  • 35.
    @DanielDeogun Requirement Easy to add/ remove / update functionality How do we avoid breaking things? How do we design for change? Easy to maintain
  • 36.
    @DanielDeogun Requirement Easy to add/ remove / update functionality How do we avoid breaking things? How do we design for change? Easy to maintain What does easy to maintain mean?
  • 37.
    @DanielDeogun Test Driven Development RED GREEN REFACTOR Proveneed Smallest code change Improve TDD tend to focus on how something is implemented rather than its behavior A good practice is to use BDD when doing TDD
  • 38.
    @DanielDeogun TDD Á laBDD public void test_ticker() { Ticker ticker = new Ticker(); ticker.increment(); assertEquals(1, ticker.value()); } TDD
  • 39.
    @DanielDeogun TDD Á laBDD public void test_ticker() { Ticker ticker = new Ticker(); ticker.increment(); assertEquals(1, ticker.value()); } TDD public void should_increment_ticker() { givenTickerWithRandomStart(); int expectedValue = ticker.value() + ticker.incrementStep(); ticker.increment(); thenTickerIsIncrementedTo(expectedValue); } TDD á la BDD
  • 40.
    @DanielDeogun TDD Á laBDD public void test_ticker() { Ticker ticker = new Ticker(); ticker.increment(); assertEquals(1, ticker.value()); } ! - Never verify more than one behavior in each test - Don’t use a common set up method TDD public void should_increment_ticker() { givenTickerWithRandomStart(); int expectedValue = ticker.value() + ticker.incrementStep(); ticker.increment(); thenTickerIsIncrementedTo(expectedValue); } TDD á la BDD
  • 41.
    @DanielDeogun Mocks “…mock objects aresimulated objects that mimic the behavior of real objects in controlled ways. A programmer typically creates a mock object to test the behavior of some other object, …” https://en.wikipedia.org/wiki/Mock_object
  • 42.
    @DanielDeogun Use DI toInject Mocks private final List<Item> items = mock(List.class);
 private final ShoppingCart shoppingCart = new ShoppingCart(items); public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean add(final Item item) {
 return items.add(notNull(item));
 }
 
 public boolean remove(final Item item) {
 return items.remove(notNull(item));
 }
 …
  • 43.
    @DanielDeogun The Great Frustration Incorrectmocking makes you spend more time updating test code than production code And the reason is…
  • 44.
    @DanielDeogun The Great Frustration Incorrectmocking makes you spend more time updating test code than production code And the reason is… Nobody puts Barbra in the corner!
  • 45.
    @DanielDeogun Violating LSP Yield BrittleTests private final List<Item> items = mock(List.class);
 private final ShoppingCart shoppingCart = new ShoppingCart(items); public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean add(final Item item) {
 return items.add(notNull(item));
 }
 
 public boolean remove(final Item item) {
 return items.remove(notNull(item));
 }
 …
  • 46.
    @DanielDeogun Violating LSP Yield BrittleTests @Test
 public void should_remove_item() {
 final Item coke = new Coke();
 BDDMockito.given(items.remove(coke)).willReturn(true);
 
 final boolean result = shoppingCart.remove(coke);
 
 assertTrue(result);
 } public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean remove(final Item item) { return items.remove(notNull(item)); }
 …
  • 47.
    @DanielDeogun Violating LSP Yield BrittleTests @Test
 public void should_remove_item() {
 final Item coke = new Coke();
 BDDMockito.given(items.remove(coke)).willReturn(true);
 
 final boolean result = shoppingCart.remove(coke);
 
 assertTrue(result);
 } public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean remove(final Item item) { return items.remove(notNull(item)); }
 … public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean remove(final Item item) {
 return items.removeAll(items.stream()
 .filter(i -> i.equals(item))
 .collect(toList()));
 }
  • 48.
    @DanielDeogun Violating LSP Yield BrittleTests @Test
 public void should_remove_item() {
 final Item coke = new Coke();
 BDDMockito.given(items.remove(coke)).willReturn(true);
 
 final boolean result = shoppingCart.remove(coke);
 
 assertTrue(result);
 } public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean remove(final Item item) { return items.remove(notNull(item)); }
 … public class ShoppingCart {
 private final List<Item> items;
 
 public ShoppingCart(final List<Item> items) {
 this.items = notNull(items);
 }
 
 public boolean remove(final Item item) {
 return items.removeAll(items.stream()
 .filter(i -> i.equals(item))
 .collect(toList()));
 } java.lang.NullPointerException
  • 49.
    @DanielDeogun Analysis The “items” mockdoesn’t satisfy LSP Invoking an unmocked method on the items object causes a failure Beware: Mockito uses default mocking behavior on some types (e.g. List, int, boolean, etc) private final List<Item> items = mock(List.class);
 private final ShoppingCart shoppingCart = new ShoppingCart(items);
  • 50.
    @DanielDeogun Tip of theDay Make domain classes final to “prevent“ mocking! [8] org.mockito.exceptions.base.MockitoException: Cannot mock/spy class se.omegapoint.opkoko.MyDomainClass Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types
  • 51.
    @DanielDeogun Branch By Code UsingFeature Toggles http://martinfowler.com/articles/feature-toggles.html
  • 52.
    @DanielDeogun Branch By Code UsingFeature Toggles Release toggles • Compile time dependency • Ex: use DI and start app with different configuration Ops toggles • Runtime dependency • Ex: special API only available for operations Experiment toggles • Runtime dependency used for A/B testing • Ex: toggle is based on user information Permission toggles • Runtime dependency • Ex: Toggle is based on payment information
  • 53.
    @DanielDeogun How Do FeatureToggles Affect Testing? Release toggles • test what’s enabled (in production) Ops toggles • make sure they only work for operations Experiment toggles • test the selection algorithm Permission toggles • test applicability We cannot test every possible combination Make an educated choice
  • 54.
    @DanielDeogun Evaluation Easy to add/ remove / update functionality How do we avoid breaking things? How do we design for change? Easy to maintain What does easy to maintain mean?
  • 55.
    @DanielDeogun Evaluation Easy to add/ remove / update functionality How do we avoid breaking things? How do we design for change? Easy to maintain What does easy to maintain mean? √
  • 56.
    @DanielDeogun Evaluation Easy to add/ remove / update functionality How do we avoid breaking things? How do we design for change? Easy to maintain What does easy to maintain mean? √ √
  • 57.
    @DanielDeogun Evaluation Easy to add/ remove / update functionality How do we avoid breaking things? How do we design for change? Easy to maintain What does easy to maintain mean? √√? √
  • 58.
  • 59.
    @DanielDeogun Requirement How do wemeasure “resilience?” Must be resilient
  • 60.
    @DanielDeogun Requirement How do wemeasure “resilience?” How do we test resilience? Must be resilient
  • 61.
    @DanielDeogun Requirement How do wemeasure “resilience?” How do we test resilience? Can we find the “upper bound?” Must be resilient
  • 62.
  • 63.
    @DanielDeogun Circuit Breaker “A circuitbreaker is an automatically operated electrical switch designed to protect an electrical circuit from damage caused by overcurrent or overload or short circuit.” - https://en.wikipedia.org/wiki/Circuit_breaker
  • 64.
  • 65.
    @DanielDeogun Schematic view ofa Circuit Breaker - Release It! Michael Nygard, The Pragmatic Bookshelf
  • 66.
  • 67.
    @DanielDeogun Separate Thread Pools AvoidCascading Failures circuit breakers Separate thread pools
  • 68.
  • 69.
    @DanielDeogun “Internal” Resilience [5] Bad inputdata Corrupt responses Design by Contract Message driven Domain Driven Design Null values Default values Immutability Concurrency
  • 70.
    @DanielDeogun Hostile Environment Imagine anenvironment whose only purpose is to bring your application to its knees Each endpoint is a potential “threat” Put your application under heavy load, inject bad input, return corrupt data, etc Make this a stage in your delivery pipeline Monitor memory consumption, response times, etc
  • 71.
    @DanielDeogun Evaluation How do wemeasure “resilience?” How do we test resilience? Must be resilient Can we find the “upper bound?”
  • 72.
    @DanielDeogun Evaluation How do wemeasure “resilience?” How do we test resilience? Must be resilient Can we find the “upper bound?” √?
  • 73.
    @DanielDeogun Evaluation How do wemeasure “resilience?” How do we test resilience? Must be resilient √ Can we find the “upper bound?” √?
  • 74.
    @DanielDeogun Evaluation How do wemeasure “resilience?” How do we test resilience? Must be resilient √ √ Can we find the “upper bound?” √?
  • 75.
    @DanielDeogun The Spec ofthe New “System” Easy to add / remove / update functionality Have same functionality as the “old” system Must be resilient Easy to maintain
  • 76.
    @DanielDeogun Conclusion - Put thetest hat on when designing a system - Testing is quite hard and require a lot of good design - You get pretty far by thinking test first
  • 77.
  • 78.
  • 79.
    @DanielDeogun References [1] Torsten, mathteacher, https://flic.kr/p/ndFN4Q License: https://creativecommons.org/licenses/by/2.0/ [2] Emily Moe, IMG_7788, https://flic.kr/p/aH4rwk, License: https://creativecommons.org/licenses/by-nd/2.0/ [3] Liskov’s Substitution Principle, Wikipedia, https://en.wikipedia.org/wiki/Liskov_substitution_principle [4] Tsutomu Takasu, Horse racing event, https://flic.kr/p/6Yy3NZ, License: https://creativecommons.org/licenses/by/2.0/ [5] http://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Emblem-evil-computer.svg/500px-Emblem-evil-computer.svg.png [6] Huey, Dewey, and Louie Duck, drawn by cartoonist Carl Barks, https://en.wikipedia.org/wiki/File:Louie_Dewey_and_Huey.png [7] Questions, https://flic.kr/p/9ksxQa] by Damián Navas, License: https://creativecommons.org/licenses/by-nc-nd/2.0/ [8] Chuck Coker, Light Bulb No. 1, https://flic.kr/p/66KLFn, License: https://creativecommons.org/licenses/by-nd/2.0/ [9] DRVMX, Titantic, https://flic.kr/p/gNLK84, License: https://creativecommons.org/licenses/by-nd/2.0/