any kind of manual verification Bad IResult result = format.execute(); System.out.println(result.size()); Iterator iter = result.iterator(); while (iter.hasNext()) { IResult r = (IResult) iter.next(); System.out.println(r. getMessage()); } Good IResult result = format.execute(); assertThat(result.size()).isEqualTo (3); Iterator iter = result.iterator(); while (iter.hasNext()) { IResult r = (IResult) iter.next(); assertThat(r.getMessage()). contains("error"); }
your team) take care about them every day Bad class SystemAdminSmokeTest extends GroovyTestCase { void testSmoke() { // do not remove below code // def ds = new org.h2.jdbcx.JdbcDataSource( // URL: 'jdbc:h2:mem:test;DB_CLOSE_DELAY=-1; MODE=Oracle', // user: 'sa', password: '') // // def jpaProperties = new Properties() // jpaProperties.setProperty( // 'hibernate.cache.use_second_level_cache', 'false') // jpaProperties.setProperty( // ) ... } • Good intentions are not enough • Writing and maintaining tests is an effort which has to be taken by the whole team
make dependency explicit) ◦ do not modify global state (system properties, file system...) • Single Responsibility Principle ◦ Each test method should verify one scenario ▪ test should have one and only one reason to fail ◦ Why? ◦ such test methods are pretty simple to understand, ◦ if they fail you know *exactly* which functionality
at a time forget about methods! TIP: Watch the method names. Are they intention- revealing? TIP: No logic in tests! Even the simplest one is evil! BAD GOOD • abstract from implementation
objects which are irrelevant to the tested scenario • distracts the reader from the testing scenario Tip: • Creating objects only to create other objects so you can create other objects? Do not do that!
user = new User(); userService.save(user); assertEquals(dao.getNbOfUsers(), 1); } 1. it does not really verify if the user was added, 2. it makes some assumptions regarding the state of the database before it is executed Good @Test public void shouldAddAUser() { int nb = dao.getNbOfUsers(); User user = new User(); userService.save(user); assertEquals(dao.getNbOfUsers(), nb + 1); } • Do not make assumptions about the database content. • Use relative rather than absolute values
= new MockServer(responseMap, true, new URL(SERVER_ROOT).getPort(), false); Good • private static final boolean RESPONSE_IS_A_FILE = true; private static final boolean NO_SSL = false; server = new MockServer(responseMap, RESPONSE_IS_A_FILE, new URL(SERVER_ROOT).getPort(), NO_SSL); • server = createFileNonSSLMockServer(responseMap);
◦ Relation to focused tests • “should” is better than “test” ◦ Start with "should". Think about scenario Starting test method names with “should” steers you in the right direction. “test” prefix makes your test method a limitless bag where you throw everything worth testing
use the right tool for the job and learn to use it! • do not live with broken windows • keep it simple • write good code, and you will also write good tests • or rather write good tests and you will get good code for free • code review your tests • do more than happy path testing • do not make the reader learn the API, make it obvious • bad names lead to bad tests • make tests readable using matchers, builders and good names • test behaviour not methods • automate! • always concentrate on what is worth testing • use the front door – state testing before interaction testing (mocks)