Test Driven Development – Using JUnit, Mockito and Hamcrest for Java



Test Driven Development – Using JUnit, Mockito and Hamcrest for Java

0 0


tdd-mockito-hamcrest-slides

Slides for TDD in Java with Mockito and Hamcrest talk

On Github phillamond / tdd-mockito-hamcrest-slides

Test Driven Development

Using JUnit, Mockito and Hamcrest for Java

Phil Lamond

This talk is about TDD in Java using JUnit, and combining with Mockito for dynamic mocking and Hamcrest matchers to provide descriptive assertions.

Coming up:

Phil's Experience of TDD What Is Test Driven Development Schools of TDD Why do TDD? What Is Mocking, Stubbing and Spying? Worked Example/Demo Techniques For Adoption Recommended Reading and Salient Hyperlinks Any Questions? Lunch and Pontification!

My experience of TDD

(at the BBC)

- introduced to idea of TDD in 2005 at BBC iF&L - tended to write tests after the fact - no xUnit pattern test framework for the Perl programming language at the time - was introduced to Java and JUnit a couple of years later - often had trouble setting up dependencies in unit tests - was introduced to Mockito and Hamcrest by a colleague and then received training

What Is Test Driven Development?

"Test-driven development is a way of managing fear during programming" - Kent Beck

Test harness for production code by writing the tests FIRST

Test the behaviours of program units

Describe those behaviours

Fear caused by not being able to see the end solution of a problem from the beginning. Fear has negative effects. It makes you: - tentative - less communicative - shy away from feedback - grumpy

What Is Test Driven Development?

By specifying required behaviours in tests, production code design can be aided

Characterised by the test-code-refactor cycle

Also known as the 'red-green-refactor cycle': - Red: write a little test that doesn't work, and perhaps doesn't even compile at first - Green: make the tests work quickly, committing whatever sins necessaryin the process - Refactor: eliminate all of the duplication created in merely getting the test to work

What Is Test Driven Development?

If done consistently production code tends to end up with ~90% test coverage

Canonical text is ‘Test Driven Development by Example’ by Kent Beck(credited with creating the Extreme Programming movement and Agile software development - aka TDD...)

Heavily influences the modern-day Software Craftsmanship movement

Schools of TDD

Classic TDD

London School (Mockist)

Check what Jason Gorman has to say about it

Classic TDD

Often seen as algorithmic in emphasis

Integer -> roman numerals pseudo-code example (from Gorman's blog)

Test #1: 1 = I -> return "I"

Test #2: 2 = II -> if integer = 1 return "I" else return "II"

Test #3: 3 = III -> while(integer > 0) concatenate "I" to result and decrement integer

Triangulate (not strangulate) through the addition of tests until the general solution is found

Start with the simplest test "roman numeral for 1 is I". The simplest solution might be to return the hardcoded literal value "I". Then we move on to the next easiest failing test

London School (Mockist)

Focuses on roles, responsibilities and collaborator interactions (as opposed to algorithms)

Design emphasis is message passing based (as opposed to algorithmic)

London School (Mockist)

General modus operandi:

Identify roles (interfaces), what they are responsible for and what their colloborators are, using SOLID style principles. This can be done in the tests Write a test for a behaviour on the subject under test, faking or mocking its immediate collaborators (dependencies) Set up the expectations of what queries on mocks will return Write verifications for the interactions the subject-under-test should have had with its collaborators

London School (Mockist)

Use mocking library matchers to constrain method parameters

Hamcrest matchers can be used in assertions about output of a method invocation for object equality or part equality

Dynamic mocking/stubbing frameworks: Mockito, JMock and EasyMock

Also PowerMock(ito) for extreme cases (mocking static or final classes/methods)

Strongly supports the Dependency Inversion pattern (constructor or setter injection of dependencies)

Hamcrest (ported across multiple languages). Mocking frameworks also have their own matchers, mainly for parameters

Example JUnit test using Mockito & Hamcrest

@RunWith(MockitoJUnitRunner.class)
public class ThingWithBehaviourTest {

    @Mock
    private CombobulationConvertor combobulationConvertor;

    @Mock
    private LaunchParser launchParser;

    private ThingWithBehaviour thing;

    @Before
    public void setUp() {
        // subject under test
        thing = new ThingWithBehaviour(launchParser, combobulationConvertor);
    }

    @Test
    public void shouldCombobulateSuccesfully() {
        CombobulationConfig combobulationConfig = new CombobulationConfig();
        String configJson = "{\"some\":\"json\"}";
        Combobulation givenCombobulation = new Combobulation();

        // check that dependencies are called with the correct parameters
        when(launchParser.parse(configJson)).thenReturn(combobulationConfig);
        when(combobulationConvertor.convert(combobulationConfig)).thenReturn(givenCombobulation);

        // invoke the subject under test
        Combobulation actualCombobulation = thing.combobulate(configJson);

        // check invocation interactions with mocked dependencies
        verify(launchParser, times(1)).parse(configJson);
        verify(combobulationConvertor, times(1)).convert(combobulationConfig);

        // check that the same instance of a Combobulation is bubbled up by the SUT
        assertThat(actualCombobulation, is(sameInstance(givenCombobulation)));
    }
}

Mockito static 'when' and 'thenReturn' methods can be swapped for the more descriptive English BDDMockito statics 'given' amd 'willReturn'

Other features of Mockito: Spies, argument captors, custom argument matchers (argThat), multiple expectations on behaviour stubs. Spies wrap real objects and allow you to modify their behaviour

Why do TDD?

Leads to less bug-ridden, ball-of-mud code, with 1000-line long classes with massive methods that do too many things, and that have intertwined behaviours that are too closely coupled

So cleaner, more readable code

A comprehensive regression harness develops

Your production code is protected against accidental breakage upon well-intended change

A comprehensive regression harness develops, protecting your production code against accidental breakage upon well-intended change

Worked Example/Demo - Postman Pat Special Delivery Service Booking System

Here's one I made earlier

Techniques For Adoption

Training e.g. by people like Jason Gorman or at Skillsmatter

Pair programming e.g. doing ping-pong

Just doing it (requires a degree of self-discipline)

Ping-pong: one developer writes a test, the other implements, then vice-versa.

Where TDD is Not Recomended

Security software (element of human judgement about the methods used to secure software)

Testing concurrency (it's still possible to get general interaction coverage though)

Key Figures, Recommended Reading and Salient Hyperlinks

Kent Beck ('father of XP and TDD') - author of Test Driven Development by Example and Extreme Programming Explained

Ward Cunningham (inventor of the wiki) - contributed to CRC cards and XP methodologies of OO software development

Robert C. Martin (aka Uncle Bob, TDD and clean code exponent) - author of Clean code, The Clean Coder and Extreme Programming in Practice

Michael Feathers - author of Working Effectively with Legacy Code

Key Figures, Recommended Reading and Salient Hyperlinks

Steve Freeman - co-author of Growing Object-Oriented Software, Guided by Tests

Nat Pryce - co-author of Growing Object-Oriented Software, Guided by Tests

(Both the above were involved in the XTC - Extreme Tuesday Club in London - out of which came their book)

Jason Gorman - software craftsmanship blogger and trainer

Any Questions?

Please be nice!

These slides: http://tdd-mockito-hamcrest.paperplane.io/

Lunch and Discussion!