TDD++: TDD Made Easier
2016-10-04 OX:AGILE Meetup @Elsevier
Christian Hujer, Software Craftsman
(Nelkinda Software Craft, Equal Experts)
Topics
● Definitions of Unit Testing
● Definitions of (A)TDD
● How (A)TDD relates to XP, Agile, Software Craftsmanship
● How (A)TDD relates to software architecture
● The Three Laws of TDD
● Unit Test vs Acceptance Test / White Box vs Black Box / Bottom-Up vs
Top-Down: When to use which approach
● The 4 A’s — Arrange, Act, Assert, Annihilate
● BDD
● The Anatomy of xUnit Frameworks (JUnit, AceUnit)
● Cucumber, Gherkin
● TPP
What makes TDD
difficult?
When did you learn programming?
When did you learn about TDD?
How many years of difference?
Is Test-Development the same as Production-
Development? What is different?
Ask yourself
TDD can be hard because …
●… writing tests is somewhat different from
writing production code.
●… we have much less experience in writing
tests than writing production code.
●… we don’t know rules, laws, guidelines,
principles.
●… we might follow bad practices.
Some Basics
The Influence of Test-
Driven Development on
Software Architecture
Number one benefit of TDD:
It supports courage!
REMOVE FEAR!
(From Robert C. Martin)
The Two Values
of Software
“The secondary value of Software is its behavior:
That it does what the current users currently need
without any bugs, crashes or delays.”
— Robert C. Martin
⇒ But: Users and their needs change with time!
Secondary Value of Software
Primary Value of Software
“The ability of software to tolerate and facilitate
such ongoing change is the primary value of
software. The primary value of software is that it’s
soft.”
— Robert C. Martin
Refactoring
Refactoring, n:
A change to the structure of source code
without significantly changing its behavior.
But what defines what change in behavior is
significant?
●Rigidity
●Fragility
●Immobility
●Viscosity
⇒ What causes them?
The Four Design Smells
Architecture in 3 Words
Coupling and Cohesion
(Surprising?) Synonyms
Testable
Reusable
Independently Developable
Independently Deployable
Decoupled
Are synonyms!
⇒ Testing requires and encourages good architecture!
Test?
What’s a Test?
A Test is an Executable Specification of
Relevant Behavior.
A Test operates by Observation of Behavior.
“Unit Tests are tests that run fast.”
— Michael Feathers,
Working Effectively with Legacy Code
What are Unit Tests?
Acceptance Test
Tests on the level of a system’s users.
Ideally they match acceptance criteria of user
stories.
Pro Tip: Write Acceptance Criteria in Gherkin!
White / Black / Grey Box
Good Unit Tests are Grey Box Tests.
(Or Black Box Tests on Class Level.)
Full White Box results in tight coupling between
Test and Implementation.
●Do not couple your unit tests to your
implementation or environment.
●Clean Code, SOLID and package principles,
DRY also apply to tests.
●Do not test private methods.
(Unit) Tests are System Components
Low Code Coverage ⇒ Low Requirements Coverage
⇒ Low Code Coverage is a strong metric.
High Code Coverage ⇏ High Requirements Coverage
⇒ High Code Coverage is a weak metric!
Execution is not sufficient.
Verification is essential!
Coverage
How to find that your test is useless
Sabotage your production
code to find useless tests.
If replacing a complex
implementation with
return "";
still passes, you’ve mocked
yourself away!
Regression Test
●Regression Test is NOT another type of test!
●Regression Test is the repeated execution of
tests in order to prevent regression.
●But: Regression Tests can be those tests
found to not change for a new feature.
Test Pyramid
Unit Tests
Acceptance
Tests
UI
Tests
Fast
Automated
Independent
Rerunnable
FAIR mnemonic acronym
Fast
Isolated
Repeatable
Self-Verifying
Timely
FIRST mnemonic acronym
JUnit Intro
●Kent Beck (SUnit) & Erich Gamma (Java)
●Standard for future frameworks
●xUnit (examples: NUnit, TestNG, CUnit,
CppUnit, EmbUnit, AceUnit)
JUnit History
What JUnit Provides
Test Runner Framework
Test Logging / Reporting Framework
Default Test Runner
Default Test Loggers
Automated Test Discovery (!)
Assertion Framework
JUnit Example
1 import org.junit.Test;
2 import static org.junit.Assert.*;
3
4 public class StringsTest {
5 @Test
6 public void nullHasLengthZero() {
7 assertEquals(0, Strings.length(null));
8 }
9 }
Essential JUnit Annotations
@BeforeClass
@Before
@Test
@After
@AfterClass
@Ignore
JUnit Execution Sequence
1 public class MyTest {
2 @BeforeClass
3 public static void beforeClass() {}
4 @AfterClass
5 public static void afterClass() {}
6 @Before
7 public void before() {}
8 @After
9 public void after() {}
10 @Test
11 public void test1() {}
12 @Test
13 public void test2() {}
14 }
1. beforeClass()
2. new MyTest()
3. before()
4. test1()
5. after()
6. new MyTest()
7. before()
8. test2()
9. after()
10.afterClass()
Original:
“A class should have should have only one reason to change.”
— Robert C. Martin
New:
On its level of abstraction, a software entity should have
only one reason to change.
SRP Revisited
Single Assert Rule
Every Test Case should contain only one logical assert.
Multiple assert statements are possible if they are one
assertion on a logical level.
SRP - Single Responsibility Principle applies here as well.
The 4 A’s
A test case consists of 4 Steps:
●Arrange
●Act
●Assert
●Annihilate
Bugfixing?
Fixing Bugs without Test-First risks regression!
⇒ Therefore:
1.Write Test to Reproduce Bug.
2.Fix Bug.
Do’s and Don’ts
Do Not compare boolean values
Bad
assertEquals(false, v);
assertEquals(true, v);
assertTrue(v == true);
assertFalse(v == true);
Good
assertTrue(v);
assertFalse(v);
Do separate A’s with blank lines
1 @Test
2 public void blinker() {
3 Universe horizontalBlinker = parse("...nOOO");
4 Universe verticalBlinker = parse(".On.On.O");
5
6 Universe actual = horizontalBlinker.step();
7
8 assertEquals(verticalBlinker, actual);
9 }
Do not log test steps
1 @Test
2 public void someTest() {
3 LOG.debug("Starting someTest().");
4 // …
5 LOG.debug("End of someTest().");
6 }
⇒ Pointless duplication of test runner functionality.
⇒ Silence is Golden (ancient UNIX wisdom).
⇒ Only make noise when crashing, but then make a lot!
⇒ If it’s so long that it has steps, it violates the SRP.
Do Make Given When Then Explicit
1 @Test
2 public void blinker() {
3 // Given
4 Universe horizontalBlinker = parse("...nOOO");
5 Universe verticalBlinker = parse(".On.On.O");
6
7 // When
8 Universe actual = horizontalBlinker.step();
9
10 // Then
11 assertEquals(verticalBlinker, actual);
12 }
Disabling Tests
Don’t comment out
1 // Takes too long
2 // @Test
3 public void someTest() {
4 // ...
5 }
Use @Ignore
1 @Ignore("Takes too long")
2 @Test
3 public void someTest() {
4 // ...
5 }
Disabled Tests are an Abomination!
(Almost like commented-out code.)
Don’t force OO without reason
1 class Strings {
2 int length(String s) {
3 return s != null
4 ? s.length()
5 : 0;
6 }
7 }
1 class Strings {
2 static int length(String s) {
3 return s != null
4 ? s.length()
5 : 0;
6 }
7 }
Don’t force OO without reason
1 class StringsTest {
2 @Test
3 void nullIsZero() {
4 Strings s;
5 s = new Strings();
6 assertEquals(0,
7 s.length(null));
8 }
9 }
1 class StringsTest {
2 @Test
3 void nullIsZero() {
4 assertEquals(0,
5 Strings.length(null));
6 }
7 }
Unit Tests are System Components
●Do not test private methods.
●Do not couple your unit tests to your
implementation.
Test Smells
● Complicated Setup / Fixture
● Rigid Tests
● Fragile Tests
● Test Code Duplication
● Erratic Tests
● Obscure Tests
● Slow Tests
● Unit Tests depending on external resources
Test Smells
TDD — Test-Driven
Development
TDD — Test-Driven Development
Developing Software by following the Three
Laws of Test-Driven Development.
ATDD — Acceptance-TDD
Applying / extending the principles of TDD to
Acceptance Testing.
The 3 Laws of TDD
1. You are not allowed to write any production code unless it is
to make a failing unit test pass.
2. You are not allowed to write any more of a unit test than is
sufficient to fail; and not compiling is failing.
3. You are not allowed to write any more production code than
is sufficient to pass the one failing unit test.
— Robert C. Martin
The Red-Green-Refactor Cycle
Red: Write as much of test
as is sufficient to fail.
Green: Write as much of
production code as is
sufficient to pass.
Refactor: Well, refactor!
TDD + Pair Programming: Ping Pong
1.Dev 1 Drives Red: Test Case
2.Dev 2 Drives Green: Production Code
3.Dev 2 Drives Blue: Refactor
4.Dev 2 Drives Red: Test Case
5.Dev 1 Drives Green: Production Code
6.Dev 1 Drives Blue: Refactor
⇒ Repeat
The Importance of Tests
●Much less Debugging
●Courage (required for Refactoring mercilessly)
●Documentation (executable Specs)
●Design
●Professionalism
— Robert C. Martin
Also: Trades Fragility into Rigidity!
Benefits of TDD
Importance of Test Code
You have 2 drives:
1.Production Code
2.Test Code
Somehow Backups are unavailable.
Which hard drive do you wish got lost?
Importance of Test Code
●Treat Test Code with at least as much care
and principles as the production code.
●That is, Clean Code, SOLID, DRY, Law of
Demeter etc. all apply!
Tests & Refactoring
What is Refactoring?
What is a Test?
How are they connected?
The Future Paths of Code
Project 1:
●Excellent Design
●No Tests
Project 2:
●Poor Design
●Lots of Tests
What will be the future of these projects?
TDD and Functional Programming
Functional Programming: Programming without
variable (re-)assignments.
⇒ Immutable Objects
⇒ Pure Functions
Immutable Objects and Pure Functions are
easier to test!
Test Doubles
(aka Mocks)
●Replace test objects
●Decoupling
●Speed up
●Provide information
●Provide verification
Test Doubles (aka Mocks)
Ontology of Test Doubles
TestDouble
Dummy
Stub
Spy
Mock
Fake
Original
replaces
Original has any of these characteristics:
●Non-deterministic results (time, temperature)
●States are difficult to reproduce
●Slow
●Does not (yet) exist
●Impedes testing
⇒ “Because I can” is not on the list!
⇒ “To isolate the test class” is not on the list!
Reasons for Using Test Doubles
Mocking can…
●…deteriorate test focus,
●…violate the Law of Demeter,
●…lead to fragile tests,
●…lead to worthless tests,
●…be harmful!
⇒ So use mocking judiciously!
Conclusions from Case Study
●Rigorously mock all external dependencies!
●Use mocking judiciously!
○Mocking might make you lose test focus.
●If the real code couldn’t pass the test in
place of the mock, the mock is wrong!
Guidelines for Mocking in Unit Tests
Guidelines for Dependency Injection
Use Dependency Injection judiciously!
Inject dependencies for Strategies and
Singletons, but not just because you can!
There’s nothing wrong with “good old concepts”
like static methods when they perfectly well do
the job!
Other
Classes can depend on functionality of other
classes in two ways:
●Loosely coupled, as in Aggregation
⇒ Mocks are useful
●Tightly coupled, as in Composition
⇒ Mocks are harmful
BDD — Behavior-Driven
Development
BDD — Behavior-Driven Development
Extension of TDD that makes use of a simple,
domain-specific language (usually around the
words “given”, “when”, “then”).
BDD - Behavior Driven Development
Arrange: Given
Act: When
Assert: Then
(Annihilate: Hidden nicely in the background)
4 A’s ≘ BDD
Arrange
Act
Assert
(Annihilate)
Given
When
Then
Gherkin and Cucumber
●Behavior-Driven Development
●Acceptance Test-Driven Development
What’s it about?
Given: Arrangement, Preconditions
When: Action
Then: Assertions, Verification
Given-When-Then
Gherkin Example
1 Scenario: As a User, I want to start the editor
2 Given I have just started the editor
3 Then the document name must be "<Unnamed>"
4 And the editor has focus
5 And the document must have the following content:
6 """
7 """
8 And the window title must be "Editor: <Unnamed>"
Feature: Delivery Date Prediction
Scenario: Ordering on a workday before cutoff time.
Given product id 1234 with cutoff time 13:00.
Given the current datetime is 2016-01-02T12:59.
Given DHL is my default delivery service.
When viewing that product,
Then the displayed delivery date is 2016-01-03.
Gherkin
1 Scenario: As a User, I want to load a file
2 Given I have just started the editor
3 And the file "foo.txt" has the following content:
4 """
5 Hello, World!
6 """
7 When I action "open"
8 Then I must be asked for a filename
9 When I enter the filename "foo.txt"
10 And I wait for I/O to be completed
11 Then the document must have the following content:
12 """
13 Hello, World!
14 """
15 And the document name must be "foo.txt".
Feature
Background
Scenario
Scenario Outline
Examples
|| (Data Tables)
@ (Tags)
Gherkin Keywords
Given
When
Then
And
But
""" (Doc Strings)
# (Comments)
Feature Files: *.feature
1 Feature: Simple Calculator Usage
2 Background:
3 Given the initial state of the calculator
4
5 Scenario: Add two numbers
6 When I press "10+10="
7 Then the result on the display is "20"
8
9 Scenario: Multiplying three numbers
10 When I press "2*3*4="
11 Then the result on the display is "24"
1 Feature: Calculator
2 Scenario Outline: Adding numbers
3 Given my current state is cleared,
4 When I enter the "<first number>",
5 And I press "+",
6 And I enter the "<second number>",
7 And I press "=",
8 Then the result must be "<sum>".
9 Examples:
10 | first number | second number | sum |
11 | 10 | 20 | 30 |
12 | 20 | 5 | 25 |
13 | 30 | 1 | 31 |
Scenario Outline Example
Smartness simplifies your life
1 Feature: Calculator
2 Scenario Outline: Performing Calculations
3 When I enter "<input>"
4 Then the result must be "<output>"
5 Examples:
6 | input | output |
7 | 1+1= | 2 |
8 | 2*3*4= | 24 |
9 | 2^2^2= | 16 |
10 | 5! | 120 |
Gherkin Tips
●Be Concise.
●Use “must” for verifications that must not fail.
●Prefer Scenario Outlines over Scenarios.
●Reuse StepDefs as much as possible.
●Ignore punctuation at the end (comma, full
stop).
Compare and discuss pros / cons
1 Given a property id:"pii:42" key:"sa:userLicense" with the
following value exists:
2 """
3 foo
4 """
1 Given I POST the following payload to
"/properties/pii/id:42?key=sa:userLicense":
2 """
3 foo
4 """
Cucumber Java 7
●Annotation Based
Cucumber Java 7
Step Definitions
1 package …;
2
3 public class EditorStepdefs {
4 @Given("^I have just started the editor$")
5 public void iHaveJustStartedTheEditor() { /* … */ }
6
7 @When("^I action "([^"]*)"$")
8 public void iAction(String actionCommand) { /* … */ }
9
10 @Then("^the document must have the following content:$")
11 public void expectDoc(String text) { /* … */ }
12 }
Connecting Cucumber with JUnit
1 package com.elsevier.…;
2
3 import cucumber.api.junit.Cucumber;
4 import org.junit.runner.RunWith;
5
6 @Cucumber.Options(
7 features = { "src/test/resources/features/" },
8 glue = { "com.elsevier.….steps" }
9 )
10 @RunWith(Cucumber.class)
11 public class RunFeatures {
12 }
●Make StepDefs as reusable as possible.
●Don’t group StepDefs by Features.
●Group StepDefs by Topics / Dependencies.
Cucumber Tips
Cucumber Java 8
1 import cucumber.api.PendingException;
2 import cucumber.api.java8.En;
3 public class MyStepdefs implements En {{
4 Given("^product id (d+) with cutoff time (d+:d+)[.,]?$", (String id, String time) -> {
5 throw new cucumber.api.PendingException();
6 });
7 Given("^the current datetime is (d+-d+-d+Td+:d+)[.,]?$", (String datetime) -> {
8 throw new PendingException();
9 });
10 Given("^"([^"]+)" is my default delivery service[.,]?$", (String deliveryService) -> {
11 throw new PendingException();
12 });
13 When("^viewing that product[.,]?$", () -> {
14 throw new PendingException();
15 });
16 Then("^the displayed delivery date is (d+-d+-d+)[.,]?$", (String expectedDeliveryDate) -> {
17 throw new PendingException();
18 });
19 }}
●Syntax Highlighting of Feature Files
●Matching of steps and step definitions
●Completion of keywords
●Completion of steps
●Creation of stub step definitions (Groovy,
Java, Java 8)
●Cucumber Test Execution
●JUnit Test Execution
Support in IntelliJ IDEA
Make Gherkin Successful
Involve Product Owner / Business Analysts
Reusable Step Definitions
⇒ This requires constant attention!
Successful Usage of Cucumber…
…requires a lot of discipline from…
●…authors of feature files
●…developers providing step definitions
To ensure consistency across the whole
project.
⇒ Cucumber is an art!
TPP — Transformation
Priority Premise
TPP — Transformation Priority Premise
Premise that production code is evolved best
by writing tests which demand applying
transformations in a specific sequence.
Transformation
Transformation, n:
A change to the behavior of source code
without significantly changing its structure.
TPP - Transformation Priority
Premise
“As the tests get more specific, the code
gets more generic.”
— Robert C. Martin
List of Transformations
1. {} → nil
2. nil → constant
3. constant → constant +
4. constant → scalar
5. statement → statements
6. unconditional → if
7. scalar → array
8. array → container
9. statement → recursion
10.if → while
11.expression → function
12.variable → assignment
TPP Applied
Start: Define the most degenerate good case.
Induction: Demand the simplest transformation
possible.
How it works
●The first unit test should demand the first
transformation.
●The next unit test should demand the
simplest next transformation possible.
●Apply the simplest transformations that still
satisfy the test.
●And: Red → Green → Refactor
Rants and WTFs
●Integration Tests that don’t Integrate?!
●Separate Regression Tests???
(All Tests are Regression Tests!)
●And Mocking / Mockito is totally overused!
Where are your skills for abstraction?
Are we out of our mind?!
Possible Future Meetup Topics
● The SOLID Principles
● Beyond SOLID: Package Principles
aka Vertical vs Horizontal Architecture
● JUnit 5
● BDD with Gherkin and Cucumber-JVM
● Cucumber-Java8
● Mocking with Mockito
● SVG — Scalable Vector Graphics
Possible Future Meetup Topics
● Clean Code Refactoring: Expense Report Example
● TDD: Bowling Game Example
● (A)TDD Swing Text Editor Example
● (A)TDD Web server Example
● Functional Programming in Java 8
● Functional Programming (3 Parts)
● Unicode and Character Encodings
● Transformation Priority Premise
Possible Future Meetup Topics
● The UNIX Way To The Web — GNU make, XSLT and
NetPBM to generate stunningly fast XHTML5
● How to increase the Quality of your Website
● C and Embedded TDD with AceUnit (on Arduino and
Raspberry Pi)
Possible Future Meetup Topics
●Speakers welcome!
2016-10-22 Global Day of Coderetreat
●More than 150 cities worldwide
●https://www.meetup.com/Agile-Software-
Development-
Oxfordshire/events/234142930/
Thank you!
Questions? Feedback?
https://seasidetesting.com/2013/03/12/testing-and-the-two-values-of-software/
http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
http://programmer.97things.oreilly.com/wiki/index.php/The_Three_Laws_of_Test-Driven_Development
References

2016 10-04: tdd++: tdd made easier

  • 1.
    TDD++: TDD MadeEasier 2016-10-04 OX:AGILE Meetup @Elsevier Christian Hujer, Software Craftsman (Nelkinda Software Craft, Equal Experts)
  • 2.
    Topics ● Definitions ofUnit Testing ● Definitions of (A)TDD ● How (A)TDD relates to XP, Agile, Software Craftsmanship ● How (A)TDD relates to software architecture ● The Three Laws of TDD ● Unit Test vs Acceptance Test / White Box vs Black Box / Bottom-Up vs Top-Down: When to use which approach ● The 4 A’s — Arrange, Act, Assert, Annihilate ● BDD ● The Anatomy of xUnit Frameworks (JUnit, AceUnit) ● Cucumber, Gherkin ● TPP
  • 3.
  • 4.
    When did youlearn programming? When did you learn about TDD? How many years of difference? Is Test-Development the same as Production- Development? What is different? Ask yourself
  • 5.
    TDD can behard because … ●… writing tests is somewhat different from writing production code. ●… we have much less experience in writing tests than writing production code. ●… we don’t know rules, laws, guidelines, principles. ●… we might follow bad practices.
  • 6.
  • 7.
    The Influence ofTest- Driven Development on Software Architecture
  • 8.
    Number one benefitof TDD: It supports courage! REMOVE FEAR!
  • 9.
    (From Robert C.Martin) The Two Values of Software
  • 10.
    “The secondary valueof Software is its behavior: That it does what the current users currently need without any bugs, crashes or delays.” — Robert C. Martin ⇒ But: Users and their needs change with time! Secondary Value of Software
  • 11.
    Primary Value ofSoftware “The ability of software to tolerate and facilitate such ongoing change is the primary value of software. The primary value of software is that it’s soft.” — Robert C. Martin
  • 12.
    Refactoring Refactoring, n: A changeto the structure of source code without significantly changing its behavior. But what defines what change in behavior is significant?
  • 13.
  • 14.
    Architecture in 3Words Coupling and Cohesion
  • 15.
    (Surprising?) Synonyms Testable Reusable Independently Developable IndependentlyDeployable Decoupled Are synonyms! ⇒ Testing requires and encourages good architecture!
  • 16.
  • 17.
    What’s a Test? ATest is an Executable Specification of Relevant Behavior. A Test operates by Observation of Behavior.
  • 18.
    “Unit Tests aretests that run fast.” — Michael Feathers, Working Effectively with Legacy Code What are Unit Tests?
  • 19.
    Acceptance Test Tests onthe level of a system’s users. Ideally they match acceptance criteria of user stories. Pro Tip: Write Acceptance Criteria in Gherkin!
  • 20.
    White / Black/ Grey Box Good Unit Tests are Grey Box Tests. (Or Black Box Tests on Class Level.) Full White Box results in tight coupling between Test and Implementation.
  • 21.
    ●Do not coupleyour unit tests to your implementation or environment. ●Clean Code, SOLID and package principles, DRY also apply to tests. ●Do not test private methods. (Unit) Tests are System Components
  • 22.
    Low Code Coverage⇒ Low Requirements Coverage ⇒ Low Code Coverage is a strong metric. High Code Coverage ⇏ High Requirements Coverage ⇒ High Code Coverage is a weak metric! Execution is not sufficient. Verification is essential! Coverage
  • 23.
    How to findthat your test is useless Sabotage your production code to find useless tests. If replacing a complex implementation with return ""; still passes, you’ve mocked yourself away!
  • 24.
    Regression Test ●Regression Testis NOT another type of test! ●Regression Test is the repeated execution of tests in order to prevent regression. ●But: Regression Tests can be those tests found to not change for a new feature.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
    ●Kent Beck (SUnit)& Erich Gamma (Java) ●Standard for future frameworks ●xUnit (examples: NUnit, TestNG, CUnit, CppUnit, EmbUnit, AceUnit) JUnit History
  • 30.
    What JUnit Provides TestRunner Framework Test Logging / Reporting Framework Default Test Runner Default Test Loggers Automated Test Discovery (!) Assertion Framework
  • 31.
    JUnit Example 1 importorg.junit.Test; 2 import static org.junit.Assert.*; 3 4 public class StringsTest { 5 @Test 6 public void nullHasLengthZero() { 7 assertEquals(0, Strings.length(null)); 8 } 9 }
  • 32.
  • 33.
    JUnit Execution Sequence 1public class MyTest { 2 @BeforeClass 3 public static void beforeClass() {} 4 @AfterClass 5 public static void afterClass() {} 6 @Before 7 public void before() {} 8 @After 9 public void after() {} 10 @Test 11 public void test1() {} 12 @Test 13 public void test2() {} 14 } 1. beforeClass() 2. new MyTest() 3. before() 4. test1() 5. after() 6. new MyTest() 7. before() 8. test2() 9. after() 10.afterClass()
  • 34.
    Original: “A class shouldhave should have only one reason to change.” — Robert C. Martin New: On its level of abstraction, a software entity should have only one reason to change. SRP Revisited
  • 35.
    Single Assert Rule EveryTest Case should contain only one logical assert. Multiple assert statements are possible if they are one assertion on a logical level. SRP - Single Responsibility Principle applies here as well.
  • 36.
    The 4 A’s Atest case consists of 4 Steps: ●Arrange ●Act ●Assert ●Annihilate
  • 37.
    Bugfixing? Fixing Bugs withoutTest-First risks regression! ⇒ Therefore: 1.Write Test to Reproduce Bug. 2.Fix Bug.
  • 38.
  • 39.
    Do Not compareboolean values Bad assertEquals(false, v); assertEquals(true, v); assertTrue(v == true); assertFalse(v == true); Good assertTrue(v); assertFalse(v);
  • 40.
    Do separate A’swith blank lines 1 @Test 2 public void blinker() { 3 Universe horizontalBlinker = parse("...nOOO"); 4 Universe verticalBlinker = parse(".On.On.O"); 5 6 Universe actual = horizontalBlinker.step(); 7 8 assertEquals(verticalBlinker, actual); 9 }
  • 41.
    Do not logtest steps 1 @Test 2 public void someTest() { 3 LOG.debug("Starting someTest()."); 4 // … 5 LOG.debug("End of someTest()."); 6 } ⇒ Pointless duplication of test runner functionality. ⇒ Silence is Golden (ancient UNIX wisdom). ⇒ Only make noise when crashing, but then make a lot! ⇒ If it’s so long that it has steps, it violates the SRP.
  • 42.
    Do Make GivenWhen Then Explicit 1 @Test 2 public void blinker() { 3 // Given 4 Universe horizontalBlinker = parse("...nOOO"); 5 Universe verticalBlinker = parse(".On.On.O"); 6 7 // When 8 Universe actual = horizontalBlinker.step(); 9 10 // Then 11 assertEquals(verticalBlinker, actual); 12 }
  • 43.
    Disabling Tests Don’t commentout 1 // Takes too long 2 // @Test 3 public void someTest() { 4 // ... 5 } Use @Ignore 1 @Ignore("Takes too long") 2 @Test 3 public void someTest() { 4 // ... 5 } Disabled Tests are an Abomination! (Almost like commented-out code.)
  • 44.
    Don’t force OOwithout reason 1 class Strings { 2 int length(String s) { 3 return s != null 4 ? s.length() 5 : 0; 6 } 7 } 1 class Strings { 2 static int length(String s) { 3 return s != null 4 ? s.length() 5 : 0; 6 } 7 }
  • 45.
    Don’t force OOwithout reason 1 class StringsTest { 2 @Test 3 void nullIsZero() { 4 Strings s; 5 s = new Strings(); 6 assertEquals(0, 7 s.length(null)); 8 } 9 } 1 class StringsTest { 2 @Test 3 void nullIsZero() { 4 assertEquals(0, 5 Strings.length(null)); 6 } 7 }
  • 46.
    Unit Tests areSystem Components ●Do not test private methods. ●Do not couple your unit tests to your implementation.
  • 47.
  • 48.
    ● Complicated Setup/ Fixture ● Rigid Tests ● Fragile Tests ● Test Code Duplication ● Erratic Tests ● Obscure Tests ● Slow Tests ● Unit Tests depending on external resources Test Smells
  • 49.
  • 50.
    TDD — Test-DrivenDevelopment Developing Software by following the Three Laws of Test-Driven Development.
  • 51.
    ATDD — Acceptance-TDD Applying/ extending the principles of TDD to Acceptance Testing.
  • 52.
    The 3 Lawsof TDD 1. You are not allowed to write any production code unless it is to make a failing unit test pass. 2. You are not allowed to write any more of a unit test than is sufficient to fail; and not compiling is failing. 3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test. — Robert C. Martin
  • 53.
    The Red-Green-Refactor Cycle Red:Write as much of test as is sufficient to fail. Green: Write as much of production code as is sufficient to pass. Refactor: Well, refactor!
  • 54.
    TDD + PairProgramming: Ping Pong 1.Dev 1 Drives Red: Test Case 2.Dev 2 Drives Green: Production Code 3.Dev 2 Drives Blue: Refactor 4.Dev 2 Drives Red: Test Case 5.Dev 1 Drives Green: Production Code 6.Dev 1 Drives Blue: Refactor ⇒ Repeat
  • 55.
  • 56.
    ●Much less Debugging ●Courage(required for Refactoring mercilessly) ●Documentation (executable Specs) ●Design ●Professionalism — Robert C. Martin Also: Trades Fragility into Rigidity! Benefits of TDD
  • 57.
    Importance of TestCode You have 2 drives: 1.Production Code 2.Test Code Somehow Backups are unavailable. Which hard drive do you wish got lost?
  • 58.
    Importance of TestCode ●Treat Test Code with at least as much care and principles as the production code. ●That is, Clean Code, SOLID, DRY, Law of Demeter etc. all apply!
  • 59.
    Tests & Refactoring Whatis Refactoring? What is a Test? How are they connected?
  • 60.
    The Future Pathsof Code Project 1: ●Excellent Design ●No Tests Project 2: ●Poor Design ●Lots of Tests What will be the future of these projects?
  • 61.
    TDD and FunctionalProgramming Functional Programming: Programming without variable (re-)assignments. ⇒ Immutable Objects ⇒ Pure Functions Immutable Objects and Pure Functions are easier to test!
  • 62.
  • 63.
    ●Replace test objects ●Decoupling ●Speedup ●Provide information ●Provide verification Test Doubles (aka Mocks)
  • 64.
    Ontology of TestDoubles TestDouble Dummy Stub Spy Mock Fake Original replaces
  • 65.
    Original has anyof these characteristics: ●Non-deterministic results (time, temperature) ●States are difficult to reproduce ●Slow ●Does not (yet) exist ●Impedes testing ⇒ “Because I can” is not on the list! ⇒ “To isolate the test class” is not on the list! Reasons for Using Test Doubles
  • 67.
    Mocking can… ●…deteriorate testfocus, ●…violate the Law of Demeter, ●…lead to fragile tests, ●…lead to worthless tests, ●…be harmful! ⇒ So use mocking judiciously! Conclusions from Case Study
  • 68.
    ●Rigorously mock allexternal dependencies! ●Use mocking judiciously! ○Mocking might make you lose test focus. ●If the real code couldn’t pass the test in place of the mock, the mock is wrong! Guidelines for Mocking in Unit Tests
  • 69.
    Guidelines for DependencyInjection Use Dependency Injection judiciously! Inject dependencies for Strategies and Singletons, but not just because you can! There’s nothing wrong with “good old concepts” like static methods when they perfectly well do the job!
  • 70.
    Other Classes can dependon functionality of other classes in two ways: ●Loosely coupled, as in Aggregation ⇒ Mocks are useful ●Tightly coupled, as in Composition ⇒ Mocks are harmful
  • 71.
  • 72.
    BDD — Behavior-DrivenDevelopment Extension of TDD that makes use of a simple, domain-specific language (usually around the words “given”, “when”, “then”).
  • 73.
    BDD - BehaviorDriven Development Arrange: Given Act: When Assert: Then (Annihilate: Hidden nicely in the background)
  • 74.
    4 A’s ≘BDD Arrange Act Assert (Annihilate) Given When Then
  • 75.
  • 76.
  • 77.
    Given: Arrangement, Preconditions When:Action Then: Assertions, Verification Given-When-Then
  • 78.
    Gherkin Example 1 Scenario:As a User, I want to start the editor 2 Given I have just started the editor 3 Then the document name must be "<Unnamed>" 4 And the editor has focus 5 And the document must have the following content: 6 """ 7 """ 8 And the window title must be "Editor: <Unnamed>"
  • 79.
    Feature: Delivery DatePrediction Scenario: Ordering on a workday before cutoff time. Given product id 1234 with cutoff time 13:00. Given the current datetime is 2016-01-02T12:59. Given DHL is my default delivery service. When viewing that product, Then the displayed delivery date is 2016-01-03. Gherkin
  • 80.
    1 Scenario: Asa User, I want to load a file 2 Given I have just started the editor 3 And the file "foo.txt" has the following content: 4 """ 5 Hello, World! 6 """ 7 When I action "open" 8 Then I must be asked for a filename 9 When I enter the filename "foo.txt" 10 And I wait for I/O to be completed 11 Then the document must have the following content: 12 """ 13 Hello, World! 14 """ 15 And the document name must be "foo.txt".
  • 81.
    Feature Background Scenario Scenario Outline Examples || (DataTables) @ (Tags) Gherkin Keywords Given When Then And But """ (Doc Strings) # (Comments)
  • 82.
    Feature Files: *.feature 1Feature: Simple Calculator Usage 2 Background: 3 Given the initial state of the calculator 4 5 Scenario: Add two numbers 6 When I press "10+10=" 7 Then the result on the display is "20" 8 9 Scenario: Multiplying three numbers 10 When I press "2*3*4=" 11 Then the result on the display is "24"
  • 83.
    1 Feature: Calculator 2Scenario Outline: Adding numbers 3 Given my current state is cleared, 4 When I enter the "<first number>", 5 And I press "+", 6 And I enter the "<second number>", 7 And I press "=", 8 Then the result must be "<sum>". 9 Examples: 10 | first number | second number | sum | 11 | 10 | 20 | 30 | 12 | 20 | 5 | 25 | 13 | 30 | 1 | 31 | Scenario Outline Example
  • 84.
    Smartness simplifies yourlife 1 Feature: Calculator 2 Scenario Outline: Performing Calculations 3 When I enter "<input>" 4 Then the result must be "<output>" 5 Examples: 6 | input | output | 7 | 1+1= | 2 | 8 | 2*3*4= | 24 | 9 | 2^2^2= | 16 | 10 | 5! | 120 |
  • 85.
    Gherkin Tips ●Be Concise. ●Use“must” for verifications that must not fail. ●Prefer Scenario Outlines over Scenarios. ●Reuse StepDefs as much as possible. ●Ignore punctuation at the end (comma, full stop).
  • 86.
    Compare and discusspros / cons 1 Given a property id:"pii:42" key:"sa:userLicense" with the following value exists: 2 """ 3 foo 4 """ 1 Given I POST the following payload to "/properties/pii/id:42?key=sa:userLicense": 2 """ 3 foo 4 """
  • 87.
  • 88.
  • 89.
    Step Definitions 1 package…; 2 3 public class EditorStepdefs { 4 @Given("^I have just started the editor$") 5 public void iHaveJustStartedTheEditor() { /* … */ } 6 7 @When("^I action "([^"]*)"$") 8 public void iAction(String actionCommand) { /* … */ } 9 10 @Then("^the document must have the following content:$") 11 public void expectDoc(String text) { /* … */ } 12 }
  • 90.
    Connecting Cucumber withJUnit 1 package com.elsevier.…; 2 3 import cucumber.api.junit.Cucumber; 4 import org.junit.runner.RunWith; 5 6 @Cucumber.Options( 7 features = { "src/test/resources/features/" }, 8 glue = { "com.elsevier.….steps" } 9 ) 10 @RunWith(Cucumber.class) 11 public class RunFeatures { 12 }
  • 91.
    ●Make StepDefs asreusable as possible. ●Don’t group StepDefs by Features. ●Group StepDefs by Topics / Dependencies. Cucumber Tips
  • 92.
    Cucumber Java 8 1import cucumber.api.PendingException; 2 import cucumber.api.java8.En; 3 public class MyStepdefs implements En {{ 4 Given("^product id (d+) with cutoff time (d+:d+)[.,]?$", (String id, String time) -> { 5 throw new cucumber.api.PendingException(); 6 }); 7 Given("^the current datetime is (d+-d+-d+Td+:d+)[.,]?$", (String datetime) -> { 8 throw new PendingException(); 9 }); 10 Given("^"([^"]+)" is my default delivery service[.,]?$", (String deliveryService) -> { 11 throw new PendingException(); 12 }); 13 When("^viewing that product[.,]?$", () -> { 14 throw new PendingException(); 15 }); 16 Then("^the displayed delivery date is (d+-d+-d+)[.,]?$", (String expectedDeliveryDate) -> { 17 throw new PendingException(); 18 }); 19 }}
  • 93.
    ●Syntax Highlighting ofFeature Files ●Matching of steps and step definitions ●Completion of keywords ●Completion of steps ●Creation of stub step definitions (Groovy, Java, Java 8) ●Cucumber Test Execution ●JUnit Test Execution Support in IntelliJ IDEA
  • 94.
    Make Gherkin Successful InvolveProduct Owner / Business Analysts Reusable Step Definitions ⇒ This requires constant attention!
  • 95.
    Successful Usage ofCucumber… …requires a lot of discipline from… ●…authors of feature files ●…developers providing step definitions To ensure consistency across the whole project. ⇒ Cucumber is an art!
  • 96.
  • 97.
    TPP — TransformationPriority Premise Premise that production code is evolved best by writing tests which demand applying transformations in a specific sequence.
  • 98.
    Transformation Transformation, n: A changeto the behavior of source code without significantly changing its structure.
  • 99.
    TPP - TransformationPriority Premise “As the tests get more specific, the code gets more generic.” — Robert C. Martin
  • 100.
    List of Transformations 1.{} → nil 2. nil → constant 3. constant → constant + 4. constant → scalar 5. statement → statements 6. unconditional → if 7. scalar → array 8. array → container 9. statement → recursion 10.if → while 11.expression → function 12.variable → assignment
  • 101.
    TPP Applied Start: Definethe most degenerate good case. Induction: Demand the simplest transformation possible.
  • 102.
    How it works ●Thefirst unit test should demand the first transformation. ●The next unit test should demand the simplest next transformation possible. ●Apply the simplest transformations that still satisfy the test. ●And: Red → Green → Refactor
  • 103.
  • 104.
    ●Integration Tests thatdon’t Integrate?! ●Separate Regression Tests??? (All Tests are Regression Tests!) ●And Mocking / Mockito is totally overused! Where are your skills for abstraction? Are we out of our mind?!
  • 105.
    Possible Future MeetupTopics ● The SOLID Principles ● Beyond SOLID: Package Principles aka Vertical vs Horizontal Architecture ● JUnit 5 ● BDD with Gherkin and Cucumber-JVM ● Cucumber-Java8 ● Mocking with Mockito ● SVG — Scalable Vector Graphics
  • 106.
    Possible Future MeetupTopics ● Clean Code Refactoring: Expense Report Example ● TDD: Bowling Game Example ● (A)TDD Swing Text Editor Example ● (A)TDD Web server Example ● Functional Programming in Java 8 ● Functional Programming (3 Parts) ● Unicode and Character Encodings ● Transformation Priority Premise
  • 107.
    Possible Future MeetupTopics ● The UNIX Way To The Web — GNU make, XSLT and NetPBM to generate stunningly fast XHTML5 ● How to increase the Quality of your Website ● C and Embedded TDD with AceUnit (on Arduino and Raspberry Pi)
  • 108.
    Possible Future MeetupTopics ●Speakers welcome!
  • 109.
    2016-10-22 Global Dayof Coderetreat ●More than 150 cities worldwide ●https://www.meetup.com/Agile-Software- Development- Oxfordshire/events/234142930/
  • 110.
  • 111.