best practices unit testing

20
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 [email protected]

Upload: tricode

Post on 26-May-2015

193 views

Category:

Engineering


9 download

DESCRIPTION

A little insight on some best practices for writing good, simple and easy to maintain unit tests.

TRANSCRIPT

Page 1: Best practices unit testing

Unit testing best practicesLazo Apostolovski

Tricode BVDe Schutterij 12 -18

3905 PL VeenendaalThe Netherlands

tel: 0318 - 559210 fax: 0318 - 650909

[email protected]

Page 2: Best practices unit testing

Experience is a hard teacher because she gives the test first, the lesson afterward.

— Chinese proverb

Page 3: Best practices unit testing

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);}

Page 4: Best practices unit testing

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);}

Page 5: Best practices unit testing

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")); }}

Page 6: Best practices unit testing

Don’t test POJO objectspublic 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"));}

Page 7: Best practices unit testing

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

Page 8: Best practices unit testing

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();}

Page 9: Best practices unit testing

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);}

Page 10: Best practices unit testing

Test one code unit on a time

@Testpublic void multiple() { Service service = new Service(); assertThat(service.doSomething(), is("something")); assertThat(service.calculate(), is(10));}

public class Service { public String doSomething() { return "something"; } public Integer calculate() { return 10; }}

Page 11: Best practices unit testing

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));}

Page 12: Best practices unit testing

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"));}

Page 13: Best practices unit testing

Design is not just what it looks like and feels like. Design is how it works.

— Steve Jobs

Page 14: Best practices unit testing

If test get complicated, we need better 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

How to indicate bad code design?

Page 15: Best practices unit testing

Give tests good names

● shouldCreateNewUserForGivenUsername

● shouldThrowExceptionWhenUsernameIsNull

● shouldStoreUserToDatabase

● shouldActivateUserByUsername

● shouldEncryptUserPassword

● shouldValidateUserPassword

Page 16: Best practices unit testing

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.

Page 17: Best practices unit testing

Add new tests for every bug you find

• 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

How will this help us?

Page 18: Best practices unit testing

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))); }}

Page 19: Best practices unit testing

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

Page 20: Best practices unit testing

Follow us:tricode.nlfacebook.com/tricodelinkedin.com/company/tricodeslideshare.net/tricodetwitter.com/tricode