test doubles, mocks, and matchers - ldstech •understanding what a test double is •creating mocks...

Post on 13-Jun-2018

215 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Test Doubles, Mocks, and Matchers

Jeremy Lund

Notes

• This is a training, NOT a presentation

• Please ask questions

• This is being recorded

• https://tech.lds.org/wiki/Java_Stack_Training

• Prerequisites

– Basic Java

– Installed LDSTech IDE (or other equivalent)

– “Unit Testing with TestNG” training

Agenda

• Understanding what a test double is

• Creating mocks using Mockito

• Better test expressions using Hamcrest Matchers

Structure of a Unit Test

Arrange Act Assert

Structure of a Unit Test

Arrange Given

Act When

Assert Then

Structure of a Unit Test

@Test

public void isValidReturnsFalseWhenNameIsEmpty() {

// Arrange / Given

Person person = new Person();

person.setName(“”);

// Act / When

person.validate();

// Assert / Then

assertFalse(person.isValid());

}

org.lds.stack.training.mocks.examples.PersonTest

Testing Collaborators

App Controller

Category Service

Person Service

Test Collaborators

@Test

public void appControllerTest() {

// Arrange / Given

CategoryService cService =

new CategoryService(categoryRepo);

PersonService pService =

new PersonService(personRepo);

AppController appController =

new AppController(cService, pService);

// Act / When

// … run the tested actions …

// Assert / Then

// … perform some assertions …

}

Test Collaborators

@Test

public void appControllerTest() {

// Arrange / Given

CategoryService cService =

new CategoryService(categoryRepo);

PersonService pService =

new PersonService(personRepo);

AppController appController =

new AppController(cService, pService);

// Act / When

// … run the tested actions …

// Assert / Then

// … perform some assertions …

}

Testing Collaborators

App Controller

Category Service

Category Repository

Person Service

Person Search Service

Person Repository

Testing Collaborators

App Controller

Category Service

Category Repository

Jdbc Template

Category Row Mapper

Person Service

Person Search Service

Entity Manager

Person Repository

Jdbc Template

Person Row Mapper

Testing Collaborators

App Controller

Category Service

Category Repository

Jdbc Template Data Source

Category Row Mapper

Person Service

Person Search Service

Entity Manager

Person Repository

Jdbc Template Data Source

Person Row Mapper

Testing Collaborators

App Controller

Category Service

Person Service

Testing Collaborators

App Controller

Category Service

Category Repository

Jdbc Template Data Source

Category Row Mapper

Person Service

Person Search Service

Entity Manager

Person Repository

Jdbc Template Data Source

Person Row Mapper

Testing Collaborators

App Controller

Category Service

Category Repository

Jdbc Template Data Source

Category Row Mapper

Person Service

Person Search Service

Entity Manager

Person Repository

Jdbc Template Data Source

Person Row Mapper

“Gum on the Ground”

Test Doubles

Benefits of Test Doubles

• Setup

• Flexibility

• Code isolation

• Introduce deterministic behavior

• Performance

Types of Test Doubles

• Test stub

• Fake object

• Test spy

• Mock object

Which Should I Use?

• “It depends”

• Ask the question: do you need the collaborator to actually DO something with the input?

• Start with Mockito, refine if necessary

Enter: Mockito

• Somewhat based off of EasyMock

• Goal: cleaner mocking in tests

– High signal, low noise

• Techically a Test Spy

Traditional Mocking Framework Steps

Expect Run Verify

Mockito Mocking Steps

Expect

(if you care) Run

Verify

(if you care)

Adding to a Stack 3.2 Project

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

</dependency>

<!-- optional, but recommended -->

<dependency>

<groupId>org.hamcrest</groupId>

<artifactId>hamcrest-library</artifactId>

</dependency>

Adding to Other Maven Projects

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

<version>1.9.0</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.hamcrest</groupId>

<artifactId>hamcrest-library</artifactId>

<version>1.2.1</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.objenesis</groupId>

<artifactId>objenesis</artifactId>

<version>1.0</version>

<scope>test</scope>

</dependency>

Defining a Mock

import static org.mockito.Mockito.*;

ClassUnderTest obj = Mockito.mock(ClassUnderTest.class);

// More common to use static import

ClassUnderTest obj = mock(ClassUnderTest.class);

org.lds.stack.training.mocks.examples.GreeterTest

Mock Behavior – Expectations and Stubs

ClassUnderTest obj = mock(ClassUnderTest.class);

// By default, methods return uninitialized value

// (null, 0, 0L, false, etc.)

// Always returns 42, no matter how many times called.

when(obj.getAnswer()).thenReturn(42);

// Returns true, then false for future interactions.

when(obj.isAwesome()).thenReturn(true).thenReturn(false);

// Void methods

// (code not available for comment)

// Throwing exceptions

when(obj.getStuff()).thenThrow(new FailException());

doThrow(new OtherException()).when(obj).doStuff(); // void

Mock Verification

// Given

ClassUnderTest obj = mock(ClassUnderTest.class);

// When

// Actions under test

// Then

// NOTE: this verifies that it happened exactly once.

verify(obj).doStuff();

// Verifies that an action never happened

// Other modifiers:

// atLeastOnce(), times(n), atMost(n), atLeast(n)

verify(obj, never()).doStuff();

// Verifies that an action occurred at least once

verify(obj, atLeastOnce()).doStuff();

Argument Matchers

// Given

Translator obj = mock(Translator.class);

// When

when(obj.getGreeting(Locale.ENGLISH)).thenReturn(“Hello”);

when(obj.getGreeting(Locale.FRENCH)).thenReturn(“Bon Jour”);

// everything else returns null

when(obj.getFarewell(any(Locale.class)).thenReturn(“BRB”);

when(obj.getFarewell(Locale.ENGLISH)).thenReturn(“Goodbye”);

when(obj.getFarewell(Locale.FRENCH)).thenReturn(“Au revoir”);

Argument Matchers

• any(), any(Class<T>)

• any…(): anyInt(), anyString(), etc.

• any…Of(Class<T>): anyListOf(Class<T>)

• eq(Obj obj): this is the default

• matches(String regex)

• startsWith(String), endsWith(String)

• argThat(Matcher<T>)

• …That(Matcher<T>): intThat(Matcher<Integer>)

Lab 1

Argument Captors

Argument Captors - Syntax

Translator obj = mock(Translator.class);

// create captor

ArgumentCaptor<Locale> localeCaptor =

ArgumentCaptor.forClass(Locale.class);

// Use the captor as an argument matcher

when(obj.getGreeting(localeCaptor.capture()))

.thenReturn(“Hello”);

// … call code that uses mock …

// Get value from last call to obj.getGreeting().

Locale value = localeCaptor.getValue();

// Returns a list of all captured values, in order.

List<Locale> values = localeCaptor.getValues();

org.lds.stack.training.mocks.examples. ContactServiceTest

Test Spies

Test Spies - Syntax

Translator obj = new TranslatorImpl();

Translator spiedOn = spy(obj);

doReturn(100).when(spiedOn).getDictionarySize();

assertEquals(spiedOn.getDictionarySize(), 100);

verify(spiedOn).getDictionarySize();

org.lds.stack.training.mocks.examples.SpyTest

Annotations – Saving the Day Since 2004

• @Mock

• @Spy

• @Captor

• @InjectMocks

NOTE: Requires a call to MockitoAnnotations.initMocks(obj);

org.lds.stack.training.mocks.examples.InjectTest

Lab 2

Hamcrest Matchers

What’s a Hamcrest Matcher?

is(equalTo(contact))

containsString(“mock”)

either(startsWith(“Test”)).or(startsWith(“Stage”))

hasPropertyWith(“address”, equalTo(“123 Fake St”))

samePropertyValuesAs(contact);

What Can I Do With Them?

assertThat();

org.lds.stack.training.mocks.examples. HamcrestAssertThatTest

Wait! There’s More!

argThat()

org.lds.stack.training.mocks.examples. HamcrestMockitoTest

Mockito Limitations

• Similar to any library that needs to dynamically extend or manipulate Java classes (think Spring AOP, libraries that use CGlib, etc.)

• Can’t mock final classes

• Can’t mock static methods

• Can’t mock final methods

• Can’t mock hashcode() or equals() (why would you?)

PowerMock Bends the Rules

PowerMock – Mocking Static Methods

@PrepareForTest(Collections.class)

public class StaticTest {

@Test

public void testStatic() {

// Tell PowerMock to mock the static methods

PowerMockito.mockStatic(Collections.class);

// Introduce mocked behavior

Mockito.when(Collections.emptyList())

.thenReturn(Arrays.<Object>asList("1", "2"));

// Try it out!

System.out.println(Collections.emptyList());

PowerMockito.verifyStatic();

org.lds.stack.training.mocks.examples.powermock.CollectionsTest

PowerMock – Mocking Finals

@PrepareForTest(FinalCountdown.class)

public class FinalTest {

@Test

public void testFinal() {

FinalCountdown finalCountdown =

PowerMockito.mock(FinalCountdown.class);

Mockito.when(finalCountdown.countdown())

.thenReturn(true, true, true, false);

Mockito.when(finalCountdown.getCurrentValue())

.thenReturn(3, 2, 1, 0);

while (finalCountdown.countdown()) {

System.out.println(

finalCountdown.getCurrentValue());

}

}

} org.lds.stack.training.mocks.examples.powermock.FinalCountdownTest

PowerMock – Mocking Private Methods

@PrepareForTest(PrivatePublic.class)

public class PrivateTest {

@Test

public void testPrivate() {

PrivatePublic privatePublic =

PowerMockito.spy(new PrivatePublic("Private"));

PowerMockito.when(privatePublic,"formatTitle")

.thenReturn("Five-Star General");

System.out.println(privatePublic.getTitle());

}

}

org.lds.stack.training.mocks.examples.powermock.PrivatePublicTest

Tips and Tricks

Don’t Mock Domain Objects

Contact contact = mock(Contact.class);

when(contact.getId()).thenReturn(15L);

when(contact.getFirstName()).thenReturn(“Chuck”);

when(contact.getLastName()).thenReturn(“Testa”);

when(contact.getStreetAddress()).thenReturn(“123 Fake St”);

when(contact.getCity()).thenReturn(“Ojai”);

when(contact.getState()).thenReturn(“CA”);

// when(does.thisEverEnd()).thenReturn(“Hooray!”);

org.lds.stack.training.mocks.examples.ContactRepositoryTest

Inject Your Collaborators

@Service

public class SuperDuperService {

private SuperService superService;

private DuperService duperService;

@Inject

public SuperDuperService(

SuperService superService,

DuperService duperService) {

this.superService = superService;

this.duperService = duperService;

}

// provide some super-duper service!

}

org.lds.stack.training.mocks.examples.SuperDuperService

Provide Reasonable Defaults

@Service

public class SuperDuperService {

private SuperService superService;

private DuperService duperService =

new DefaultDuperService();

@Inject

public SuperDuperService(SuperService superService) {

this.superService = superService;

}

public void setDuperService(DuperService duperService) {

this.duperService = duperService;

}

}

org.lds.stack.training.mocks.examples.AnotherSuperDuperService

Consider Testing When Building

What’s Next?

• Integration testing

• Test data builders

Creative Commons

Name Author URL

Lab icon 2 pitr http://openclipart.org/detail/22628/lab-icon-2-by-pitr/

Gum Alley Bev Sykes http://www.flickr.com/photos/basykes/713314598/

nuclear explosion tzunghaor http://openclipart.org/detail/166696/nuclear-explosion-by-tzunghaor

Reflections meddygarnet http://www.flickr.com/photos/meddygarnet/3457266724/

Caged Kids Morten Liebach http://www.flickr.com/photos/morten_liebach/4488573473/

FBI Dude elkbuntu http://openclipart.org/detail/10717/fbi-dude-by-elkbuntu

Creative Commons

Name Author URL

365 Day 337 Collin Harvey http://www.flickr.com/photos/celloc/6913920367/

You were the chosen one!

Kyknoord http://www.flickr.com/photos/kyknoord/2092369873/

Crash Test Dummies working on Smart Car

a200/a77Wells http://www.flickr.com/photos/aiwells/4672742619/

Wolf Memory Game Evelyn Saenz http://www.flickr.com/photos/evelynsaenz/6716600387/

top related