Unit testing best practices 
Lazo Apostolovski 
Tricode BV 
De Schutterij 12 -18 
3905 PL Veenendaal 
The Netherlands 
tel: 0318 - 559210 
fax: 0318 - 650909 
www.tricode.nl 
info@tricode.nl
Experience is a hard teacher because 
she gives the test first, the lesson 
afterward. 
— Chinese proverb
Don’t make unnecessary assertions 
@Testpublic void scenarioOne() { 
User result = service.doSomething(user); 
assertThat(result.someState(), is(“Yes”)); 
} 
@Testpublic void scenarioTwo() { 
User result = service.doSomething(user); 
assertThat(result.someState(), is(“Yes”)); 
assertThat(result.isEnabled(), is(true)); 
} 
@Testpublic void useless(){ 
assertTrue(false); 
}
Use annotation to test thrown 
exceptions 
GOOD: 
@Test(expected = 
Exception.class)public void 
testSomethig() { 
service.methodThrowsException(); 
} 
BAD: 
@Testpublic void testSomething() { 
boolean haveException = false; 
try { 
service.methodThrowsException(); 
} catch (Exception e) { 
haveException = true; 
} 
assertTrue(haveException); 
}
Don't test Java 
public class MyException extends Exception { 
public MyException(String message) { 
super(message); 
} 
} 
public void someMethod() throws MyException { 
throw new MyException("SomeMessage"); 
} 
@Testpublic void testSomething() { 
try { 
service.someMethod(); 
} catch (MyException e) { 
assertThat(e.getMessage(), is("SomeMessage")); 
} 
}
Don’t test POJO objects 
public class POJO { 
private String field; 
public String getField() { 
return field; 
} 
public void setField(String field) { 
this.field = field; 
} 
} 
@Testpublic void testPojo() { 
POJO pojo = new POJO(); 
pojo.setField("value"); 
assertThat(pojo.getField(), is("value")); 
}
I remember growing up with 
television, from the time it was 
just a test pattern, with maybe a 
little bit of programming once in a 
while. 
— Francis Ford Coppola
Mock all external services 
and states 
@Testpublic void multiple() { 
Dao dao = mock(Dao.class); 
EmailService emailService = mock(EmailService.class); 
RemoteControl remoteControl = mock(RemoteControl.class); 
Service service = new Service(dao, emailService, remoteControl); 
User user = new User(); 
doReturn(10).when(emailService).sendEmail(); 
doReturn(10).when(dao).store(user); 
service.save(user); 
verify(remoteControl, times(1)).turnOn(); 
}
Avoid unnecessary 
preconditions and 
verifications 
public class Service { 
private Dao dao; 
public Service(Dao dao) { 
this.dao = dao; 
} 
public int save(User user) { 
return dao.store(user); 
} 
} 
public interface Dao { 
public int store(Object o); 
public Object read() ; 
} 
@Testpublic void multiple() { 
Dao dao = mock(Dao.class); 
User user = new User(); 
Service service = new Service(dao); 
doReturn(new User()).when(dao).read(); 
doReturn(10).when(dao).store(user); 
assertThat(service.save(user), is(10)); 
verify(dao, times(1)).store(user); 
}
Test one code unit on a time 
public class Service { 
@Testpublic void multiple() { 
Service service = new Service(); 
assertThat(service.doSomething(), is("something")); 
assertThat(service.calculate(), is(10)); 
} 
public String doSomething() { 
return "something"; 
} 
public Integer calculate() { 
return 10; 
} 
}
Write multiple test scenarios 
public class Service { 
public String doSomething() { return "something"; } 
public Integer calculate() { return 10; } 
} 
@Testpublic void testDoSomething() { 
Service service = new Service(); 
assertThat(service.doSomething(), is("something")); 
} 
@Testpublic void testCalculate() { 
Service service = new Service(); 
assertThat(service.calculate(), is(10)); 
}
Don’t rely on indirect testing 
public class Service { 
public String doSomething() { 
return new AnotherService().doSomething(); 
} 
}public class AnotherService { 
public String doSomething() { 
return "someThing"; 
} 
} 
@Testpublic void testAnotherService() { 
Service service = new Service(); 
assertThat(service.doSomething(), is("someThing")); 
}
Design is not just what it looks like 
and feels like. Design is how it 
works. 
— Steve Jobs
If test get complicated, we 
need better code design 
How to indicate bad code design? 
• Complex test objects need to be created to test 
simple scenario (otherwise null pointers are fired) 
• More than 4 dependencies need to be mocked. 
• Test have too much mock statements for one test 
scenario 
• Test is getting more than ~5-10 lines of code. 
• If you get in any of this states,re-factor your code
Give tests good names 
● shouldCreateNewUserForGivenUsername 
● shouldThrowExceptionWhenUsernameIsNull 
● shouldStoreUserToDatabase 
● shouldActivateUserByUsername 
● shouldEncryptUserPassword 
● shouldValidateUserPassword
Don’t skip unit tests 
@Ignore 
@Testpublic void testPojo() { 
Service service = new Service(); 
assertThat(service.doSomething(), is("someThing")); 
} 
● Having invalid test cases in our 
source code will not help anyone. 
● If test scenario is invalid, then 
remove it.
Add new tests for every bug 
you find 
How will this help us? 
• Will keep an eye on a bug for us 
• Will prevent us of making changes that will make 
the bug reappear 
• It is the agile way 
• It always good to have more unit tests
Parametrize where you can 
@RunWith(value = Parameterized.class)public class Example { 
private final Service service = new Service(); 
private final String value; 
private final boolean result; 
@Parameterized.Parameters 
public static Collection<Object[]> data() { 
final Object[][] data = new Object[][]{ {StringUtils.EMPTY, Boolean.FALSE}, 
{"123_some", Boolean.FALSE}, 
{null, Boolean.TRUE}, }; 
return Arrays.asList(data); 
} 
public Example(final String value, final boolean result) { this.value = value; this.result = 
result; } 
@Test 
public void isValid() { 
assertThat(service.doSomething(value), is(equalTo(result))); 
} 
}
Final notes 
Tests are documentation tool. New developer 
can have more insight about what code do. 
Test everything that could possibly break 
Don’t test configuration settings 
Don’t test logging 
Keep tests independent
Follow us: 
tricode.nl 
facebook.com/tricode 
linkedin.com/company/tricode 
slideshare.net/tricode 
twitter.com/tricode

Best practices unit testing

  • 1.
    Unit testing bestpractices Lazo Apostolovski Tricode BV De Schutterij 12 -18 3905 PL Veenendaal The Netherlands tel: 0318 - 559210 fax: 0318 - 650909 www.tricode.nl info@tricode.nl
  • 2.
    Experience is ahard teacher because she gives the test first, the lesson afterward. — Chinese proverb
  • 3.
    Don’t make unnecessaryassertions @Testpublic void scenarioOne() { User result = service.doSomething(user); assertThat(result.someState(), is(“Yes”)); } @Testpublic void scenarioTwo() { User result = service.doSomething(user); assertThat(result.someState(), is(“Yes”)); assertThat(result.isEnabled(), is(true)); } @Testpublic void useless(){ assertTrue(false); }
  • 4.
    Use annotation totest thrown exceptions GOOD: @Test(expected = Exception.class)public void testSomethig() { service.methodThrowsException(); } BAD: @Testpublic void testSomething() { boolean haveException = false; try { service.methodThrowsException(); } catch (Exception e) { haveException = true; } assertTrue(haveException); }
  • 5.
    Don't test Java public class MyException extends Exception { public MyException(String message) { super(message); } } public void someMethod() throws MyException { throw new MyException("SomeMessage"); } @Testpublic void testSomething() { try { service.someMethod(); } catch (MyException e) { assertThat(e.getMessage(), is("SomeMessage")); } }
  • 6.
    Don’t test POJOobjects public class POJO { private String field; public String getField() { return field; } public void setField(String field) { this.field = field; } } @Testpublic void testPojo() { POJO pojo = new POJO(); pojo.setField("value"); assertThat(pojo.getField(), is("value")); }
  • 7.
    I remember growingup with television, from the time it was just a test pattern, with maybe a little bit of programming once in a while. — Francis Ford Coppola
  • 8.
    Mock all externalservices and states @Testpublic void multiple() { Dao dao = mock(Dao.class); EmailService emailService = mock(EmailService.class); RemoteControl remoteControl = mock(RemoteControl.class); Service service = new Service(dao, emailService, remoteControl); User user = new User(); doReturn(10).when(emailService).sendEmail(); doReturn(10).when(dao).store(user); service.save(user); verify(remoteControl, times(1)).turnOn(); }
  • 9.
    Avoid unnecessary preconditionsand verifications public class Service { private Dao dao; public Service(Dao dao) { this.dao = dao; } public int save(User user) { return dao.store(user); } } public interface Dao { public int store(Object o); public Object read() ; } @Testpublic void multiple() { Dao dao = mock(Dao.class); User user = new User(); Service service = new Service(dao); doReturn(new User()).when(dao).read(); doReturn(10).when(dao).store(user); assertThat(service.save(user), is(10)); verify(dao, times(1)).store(user); }
  • 10.
    Test one codeunit on a time public class Service { @Testpublic void multiple() { Service service = new Service(); assertThat(service.doSomething(), is("something")); assertThat(service.calculate(), is(10)); } public String doSomething() { return "something"; } public Integer calculate() { return 10; } }
  • 11.
    Write multiple testscenarios public class Service { public String doSomething() { return "something"; } public Integer calculate() { return 10; } } @Testpublic void testDoSomething() { Service service = new Service(); assertThat(service.doSomething(), is("something")); } @Testpublic void testCalculate() { Service service = new Service(); assertThat(service.calculate(), is(10)); }
  • 12.
    Don’t rely onindirect testing public class Service { public String doSomething() { return new AnotherService().doSomething(); } }public class AnotherService { public String doSomething() { return "someThing"; } } @Testpublic void testAnotherService() { Service service = new Service(); assertThat(service.doSomething(), is("someThing")); }
  • 13.
    Design is notjust what it looks like and feels like. Design is how it works. — Steve Jobs
  • 14.
    If test getcomplicated, we need better code design How to indicate bad code design? • Complex test objects need to be created to test simple scenario (otherwise null pointers are fired) • More than 4 dependencies need to be mocked. • Test have too much mock statements for one test scenario • Test is getting more than ~5-10 lines of code. • If you get in any of this states,re-factor your code
  • 15.
    Give tests goodnames ● shouldCreateNewUserForGivenUsername ● shouldThrowExceptionWhenUsernameIsNull ● shouldStoreUserToDatabase ● shouldActivateUserByUsername ● shouldEncryptUserPassword ● shouldValidateUserPassword
  • 16.
    Don’t skip unittests @Ignore @Testpublic void testPojo() { Service service = new Service(); assertThat(service.doSomething(), is("someThing")); } ● Having invalid test cases in our source code will not help anyone. ● If test scenario is invalid, then remove it.
  • 17.
    Add new testsfor every bug you find How will this help us? • Will keep an eye on a bug for us • Will prevent us of making changes that will make the bug reappear • It is the agile way • It always good to have more unit tests
  • 18.
    Parametrize where youcan @RunWith(value = Parameterized.class)public class Example { private final Service service = new Service(); private final String value; private final boolean result; @Parameterized.Parameters public static Collection<Object[]> data() { final Object[][] data = new Object[][]{ {StringUtils.EMPTY, Boolean.FALSE}, {"123_some", Boolean.FALSE}, {null, Boolean.TRUE}, }; return Arrays.asList(data); } public Example(final String value, final boolean result) { this.value = value; this.result = result; } @Test public void isValid() { assertThat(service.doSomething(value), is(equalTo(result))); } }
  • 19.
    Final notes Testsare documentation tool. New developer can have more insight about what code do. Test everything that could possibly break Don’t test configuration settings Don’t test logging Keep tests independent
  • 20.
    Follow us: tricode.nl facebook.com/tricode linkedin.com/company/tricode slideshare.net/tricode twitter.com/tricode