Slide 1

Slide 1 text

ELEGANT?? UNIT TESTING by Pablo Guardiola @Guardiola31337 MADRID - NOV 27-28 - 2015

Slide 2

Slide 2 text

TWITTER @Guardiola31337 BLOG pguardiola.com/blog

Slide 3

Slide 3 text

4 rules of simple design 1. Runs all the Tests

Slide 4

Slide 4 text

4 rules of simple design 1. Runs all the Tests 2. Reveals all the intention

Slide 5

Slide 5 text

4 rules of simple design 1. Runs all the Tests 2. Reveals all the intention 3. No duplication

Slide 6

Slide 6 text

4 rules of simple design 1. Runs all the Tests 2. Reveals all the intention 3. No duplication 4. Fewest number of classes or methods

Slide 7

Slide 7 text

On what are they all AGREED?

Slide 8

Slide 8 text

PASSES its tests!

Slide 9

Slide 9 text

Have you ever asked yourself, WHY? What MOTIVATES you to write tests?

Slide 10

Slide 10 text

Testing motivators Validate the System

Slide 11

Slide 11 text

Testing motivators Validate the System Code Coverage

Slide 12

Slide 12 text

Testing motivators Validate the System Code Coverage Enable Refactoring

Slide 13

Slide 13 text

Testing motivators Validate the System Code Coverage Enable Refactoring Document the Behaviour of the System

Slide 14

Slide 14 text

Testing motivators Validate the System Code Coverage Enable Refactoring Document the Behaviour of the System Your Manager Told You To

Slide 15

Slide 15 text

Testing motivators Validate the System Code Coverage Enable Refactoring Document the Behaviour of the System Your Manager Told You To Test Driven Development

Slide 16

Slide 16 text

Testing motivators Validate the System Code Coverage Enable Refactoring Document the Behaviour of the System Your Manager Told You To Test Driven Development Customer Acceptance

Slide 17

Slide 17 text

Testing motivators Validate the System Code Coverage Enable Refactoring Document the Behaviour of the System Your Manager Told You To Test Driven Development Customer Acceptance Ping-Pong Pair Programming

Slide 18

Slide 18 text

Testing motivators Validate the System Code Coverage Enable Refactoring Document the Behaviour of the System Your Manager Told You To Test Driven Development Customer Acceptance Ping-Pong Pair Programming Flow

Slide 19

Slide 19 text

Types of Tests STATE VERIFICATION

Slide 20

Slide 20 text

Types of Tests STATE VERIFICATION BEHAVIOR VERIFICATION

Slide 21

Slide 21 text

HYBRID

Slide 22

Slide 22 text

Unit Test SOLITARY 1. Never cross boundaries

Slide 23

Slide 23 text

Unit Test SOLITARY 1. Never cross boundaries 2.The Class Under Test should be the only concrete class found in a test

Slide 24

Slide 24 text

Unit Test SOLITARY SOCIABLE 1. Never cross boundaries 2.The Class Under Test should be the only concrete class found in a test

Slide 25

Slide 25 text

FIRST FAST

Slide 26

Slide 26 text

FIRST FAST INDEPENDENT

Slide 27

Slide 27 text

FIRST FAST INDEPENDENT REPEATABLE

Slide 28

Slide 28 text

FIRST FAST INDEPENDENT REPEATABLE SELF-VALIDATING

Slide 29

Slide 29 text

FIRST FAST INDEPENDENT REPEATABLE SELF-VALIDATING TIMELY

Slide 30

Slide 30 text

Test Doubles DUMMY

Slide 31

Slide 31 text

Dummy public class DummyAuthorizer implements Authorizer {
 @Override
 public Boolean authorize(String username, String password) {
 return null;
 }
 }

Slide 32

Slide 32 text

Test Doubles DUMMY STUB

Slide 33

Slide 33 text

Stub public class AcceptingAuthorizerStub implements Authorizer {
 @Override
 public Boolean authorize(String username, String password) {
 return true;
 }
 }

Slide 34

Slide 34 text

Test Doubles DUMMY STUB SPY

Slide 35

Slide 35 text

Spy public class AcceptingAuthorizerSpy implements Authorizer {
 public boolean authorizeWasCalled = false;
 
 public Boolean authorize(String username, String password) {
 authorizeWasCalled = true;
 return true;
 }
 }

Slide 36

Slide 36 text

Test Doubles DUMMY STUB SPY MOCK

Slide 37

Slide 37 text

Mock public class AcceptingAuthorizerVerificationMock implements Authorizer {
 public boolean authorizeWasCalled = false;
 
 public Boolean authorize(String username, String password) {
 authorizeWasCalled = true;
 return true;
 }
 
 public boolean verify() {
 return authorizeWasCalled;
 }
 }

Slide 38

Slide 38 text

Test Doubles DUMMY STUB SPY MOCK FAKE

Slide 39

Slide 39 text

Fake public class AcceptingAuthorizerFake implements Authorizer {
 public Boolean authorize(String username, String password) {
 return username.equals("Bob");
 }
 }

Slide 40

Slide 40 text

AAA ARRANGE

Slide 41

Slide 41 text

AAA ARRANGE ACT

Slide 42

Slide 42 text

AAA ARRANGE ACT ASSERT

Slide 43

Slide 43 text

What about ANDROID?

Slide 44

Slide 44 text

ANDROID Unit Testing Java Module

Slide 45

Slide 45 text

ANDROID Unit Testing Java Module AS 1.1 + Android Gradle Plugin

Slide 46

Slide 46 text

ANDROID Unit Testing Java Module MVP AS 1.1 + Android Gradle Plugin

Slide 47

Slide 47 text

ANDROID Unit Testing Java Module MVP AS 1.1 + Android Gradle Plugin MVVM

Slide 48

Slide 48 text

ANDROID Unit Testing Java Module MVP CLEAN Architecture AS 1.1 + Android Gradle Plugin MVVM

Slide 49

Slide 49 text

ANDROID Unit Testing Java Module MVP CLEAN Architecture AS 1.1 + Android Gradle Plugin MVVM KOR

Slide 50

Slide 50 text

ANDROID Unit Testing Java Module MVP CLEAN Architecture AS 1.1 + Android Gradle Plugin MVVM KOR Mosby (Hannes Dorfmann)

Slide 51

Slide 51 text

ANDROID Unit Testing Java Module MVP CLEAN Architecture AS 1.1 + Android Gradle Plugin MVVM KOR Catan Architecture Mosby (Hannes Dorfmann)

Slide 52

Slide 52 text

ANDROID Unit Testing Java Module MVP CLEAN Architecture AS 1.1 + Android Gradle Plugin MVVM KOR Catan Architecture Mosby (Hannes Dorfmann) Rosie?

Slide 53

Slide 53 text

DECOUPLED Architecture

Slide 54

Slide 54 text

Where do I START?

Slide 55

Slide 55 text

public class FooTest {
 
 @Test
 public void sampleTest() throws Exception {
 assertEquals(expected, actual);
 }
 } JUnit

Slide 56

Slide 56 text

Clean Contacts @Test public void obtainContactFirstNameFromRepo() throws Exception {
 ContactsBddDataSource mockContactsBddDataSource = mock(ContactsBddDataSource.class);
 ContactsNetworkDataSource mockContactsNetworkDataSource = mock(ContactsNetworkDataSource.class);
 ContactsRepositoryImp contactsRepository =
 new ContactsRepositoryImp(mockContactsNetworkDataSource, mockContactsBddDataSource);
 Contact droidCon = new Contact();
 Name name = new Name();
 name.setFirst("Codemotion 2015");
 droidCon.setName(name);
 when(mockContactsBddDataSource.obtain("Codemotion MD5")).thenReturn(droidCon);
 
 Contact contact = contactsRepository.obtain("Codemotion MD5");
 
 assertEquals("Codemotion 2015", contact.getName().getFirst());
 }

Slide 57

Slide 57 text

Clean Contacts @Test public void contactsInteractorExecutedWhenResumed() throws Exception {
 InteractorInvoker interactorInvoker = mock(InteractorInvoker.class);
 GetContactsInteractor getContactsInteractor = mock(GetContactsInteractor.class);
 final ListMapper listMapper = mock(ListMapper.class);
 ThreadSpec mainThreadSpec = mock(ThreadSpec.class);
 MainPresenter mainPresenter =
 new MainPresenter(interactorInvoker, getContactsInteractor, listMapper, mainThreadSpec);
 
 mainPresenter.onResume();
 
 verify(interactorInvoker).execute(Mockito.eq(getContactsInteractor), Mockito.any(InteractorOutputImp.class));
 }

Slide 58

Slide 58 text

How do I IMPROVE my tests? DAMP

Slide 59

Slide 59 text

One Assertion Per Test (State Verification) @Test public void shouldCreateVerboseTraceFromStringTrace() throws Exception {
 Trace trace = Trace.fromString(VERBOSE_TRACE);
 
 assertEquals(TraceLevel.VERBOSE, trace.getLevel());
 assertEquals(ANY_TRACE_DATE + " " + VERBOSE_TRACE_MESSAGE, trace.getMessage());
 }

Slide 60

Slide 60 text

ANNOYING to have to look at the STACKTRACE to know what’s FAILING

Slide 61

Slide 61 text

ANNOYING to have to look at the STACKTRACE to know what’s FAILING Have NO INFORMATION about REMAINING TESTS

Slide 62

Slide 62 text

One Assertion Per Test (Behavior Verification) @Test public void shouldNotUpdateFilterIfPresenterIsNotInitialized() {
 presenter.updateFilter(ANY_FILTER);
 
 verify(lynx, never()).setConfig(any(LynxConfig.class));
 verify(lynx, never()).restart();
 }

Slide 63

Slide 63 text

1. If your test has an assertion, do not add any mock verifications Rule of thumb

Slide 64

Slide 64 text

1. If your test has an assertion, do not add any mock verifications 2. If your test verifies a mock, do not add any assertions Rule of thumb

Slide 65

Slide 65 text

1. If your test has an assertion, do not add any mock verifications 2. If your test verifies a mock, do not add any assertions 3. At most, 1 assertion per test Rule of thumb

Slide 66

Slide 66 text

1. If your test has an assertion, do not add any mock verifications 2. If your test verifies a mock, do not add any assertions 3. At most, 1 assertion per test 4. At most, 1 mock verification per test Rule of thumb

Slide 67

Slide 67 text

Expect Literals @Test
 public void testSaveAllNextLevel() throws Exception {
 doReturn(Boolean.TRUE).when(repository).hasNextLevel();
 
 assertEquals(elements.size(), repository.saveAll(elements).size());
 verify(nextLevel, times(1)).saveAll(anyCollection());
 }

Slide 68

Slide 68 text

Expect Literals @Test
 public void testSaveAllNextLevel() throws Exception {
 doReturn(Boolean.TRUE).when(repository).hasNextLevel();
 
 assertEquals(3, repository.saveAll(elements).size());
 verify(nextLevel, times(1)).saveAll(anyCollection());
 }

Slide 69

Slide 69 text

READABILITY LITERALS will REFLECT the examples from the BUSINESS

Slide 70

Slide 70 text

Value Objects vs Expect Literals CONVERT VALUE OBJECT to a LITERAL

Slide 71

Slide 71 text

Inline Setup @Before
 public void setUp() throws Exception {
 initMocks(this);
 
 elements.add(mockedElement1);
 elements.add(mockedElement2);
 elements.add(mockedElement3);
 
 ids.add(EXPECTED_FIRST_ID);
 ids.add(EXPECTED_SECOND_ID);
 ids.add(EXPECTED_THIRD_ID);
 
 repository = new BaseFastRepositoryImpl(currentLevel, null);
 }

Slide 72

Slide 72 text

READABILITY Avoid CODE DUPLICATION? BUILDERS

Slide 73

Slide 73 text

Don’t test your stubs @Test
 public void doNotTestYourStubs() throws Exception {
 Name name = mock(Name.class);
 // blah blah blah...
 when(name.getFullName()).thenReturn("Don't test your stubs, please!");
 // 27 lines of stuff...
 assertEquals("Don't test your stubs, please!", name.getFullName());
 }

Slide 74

Slide 74 text

Separating The Solitary From The Sociable 1. Can be slow and nondeterministic Sociable Unit Tests

Slide 75

Slide 75 text

Separating The Solitary From The Sociable 1. Can be slow and nondeterministic 2. Are more susceptible to cascading failures Sociable Unit Tests

Slide 76

Slide 76 text

Questionable Tests Testing Language Features or Standard Library Classes

Slide 77

Slide 77 text

Questionable Tests Testing Language Features or Standard Library Classes Testing Framework Features or Classes

Slide 78

Slide 78 text

Should we even bother writing Unit Tests? “The key is to test the areas that you are most worried about going wrong. That way you get the most benefit for your testing effort.” Martin Fowler, Refactoring

Slide 79

Slide 79 text

“Practise makes perfect.”

Slide 80

Slide 80 text

Thank you! @Guardiola31337 pguardiola.com guardiola31337@gmail.com

Slide 81

Slide 81 text

Extreme Programming Explained: Embrace Change, Kent Beck, AddisonWesley. Working Effectively with Unit Tests by Jay Fields Bibliography Mocks Aren’t Stubs (www.martinfowler.com/articles/mocksArentStubs.html) The Little Mocker (blog.8thlight.com/uncle-bob/2014/05/14/TheLittleMocker.html) https://github.com/PaNaVTEC/Clean-Contacts https://github.com/pedrovgs/Lynx https://github.com/Sefford/kor Ted Mosby - Software Architect (http://hannesdorfmann.com/android/mosby) Responsible Design for Android by J. B. Rainsberger Clean Code: A handbook of Agile Software Craftsmanship, Robert C. Martin Software Craftsmanship by Sandro Mancuso