Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elegant?? Unit Testing (Droidcon Berlin 2016)

Elegant?? Unit Testing (Droidcon Berlin 2016)

In this session we will learn the basics of Unit Testing and its importance. We will define what a Unit Test is, what type of Unit Tests there are and then talk about Test Doubles. Finally, we will focus on how to write new tests and improve existing ones by reviewing some Android Github projects.

Can you sleep soundly without writing tests? Really???

Pablo Guardiola

June 18, 2016
Tweet

More Decks by Pablo Guardiola

Other Decks in Programming

Transcript

  1. 4 rules of simple design 1. Runs all the Tests

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

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

    2. Reveals all the intention 3. No duplication 4. Fewest classes or methods
  4. Testing motivators Validate the System Code Coverage Enable Refactoring Document

    the Behaviour of the System Test Driven Development
  5. Testing motivators Validate the System Code Coverage Enable Refactoring Document

    the Behaviour of the System Test Driven Development Customer Acceptance
  6. Testing motivators Validate the System Code Coverage Enable Refactoring Document

    the Behaviour of the System Test Driven Development Customer Acceptance …
  7. Unit Test SOLITARY 1. Never crosses boundaries 2.The Class Under

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

    Under Test should be the only concrete class found in a test
  9. Dummy public class DummyAuthorizer implements Authorizer {
 @Override
 public Boolean

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

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

    = false;
 
 public Boolean authorize(String username, String password) {
 authorizeWasCalled = true;
 return true;
 }
 }
  12. 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;
 }
 }
  13. Fake public class AcceptingAuthorizerFake implements Authorizer {
 public Boolean authorize(String

    username, String password) {
 return username.equals("Bob");
 }
 }
  14. ANDROID Unit Testing Java Module MVP CLEAN Architecture AS 1.1

    + Android Gradle Plugin MVVM Catan Architecture
  15. ANDROID Unit Testing Java Module Mosby MVP CLEAN Architecture AS

    1.1 + Android Gradle Plugin MVVM Catan Architecture
  16. ANDROID Unit Testing Java Module Rosie Mosby MVP CLEAN Architecture

    AS 1.1 + Android Gradle Plugin MVVM Catan Architecture
  17. ANDROID Unit Testing … Java Module Rosie Mosby MVP CLEAN

    Architecture AS 1.1 + Android Gradle Plugin MVVM Catan Architecture
  18. public class FooTest {
 
 @Test
 public void sampleTest() throws

    Exception {
 assertEquals(expected, actual);
 }
 } JUnit
  19. 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("droidcon Berlin");
 droidCon.setName(name);
 when(mockContactsBddDataSource.obtain(“droidcon MD5")).thenReturn(droidCon);
 
 Contact contact = contactsRepository.obtain("droidcon MD5");
 
 assertEquals("droidcon Berlin", contact.getName().getFirst());
 }
  20. Clean Contacts @Test public void contactsInteractorExecutedWhenResumed() throws Exception {
 InteractorInvoker

    interactorInvoker = mock(InteractorInvoker.class);
 GetContactsInteractor getContactsInteractor = mock(GetContactsInteractor.class);
 final ListMapper<Contact, PresentationContact> 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));
 }
  21. 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());
 }
  22. It’s ANNOYING to have to look at the STACKTRACE to

    know what’s FAILING Have NO INFORMATION about REMAINING TESTS
  23. 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();
 }
  24. 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());
 }
  25. 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());
 }
  26. Avoid 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);
 }
  27. 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());
 }
  28. 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
  29. 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/Guardiola31337/CatanArchitecture 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