Good Tests Bad Tests

22

Transcript of Good Tests Bad Tests

Page 1: Good Tests Bad Tests
Page 2: Good Tests Bad Tests

Dijkstra, The Humble Programmer 1972

Page 3: Good Tests Bad Tests

Gute Tests

● Mit jedem Test stellen wir sicher, dass die getesteteFunktionalität korrekt umgesetzt ist

● Hoffnung, dass ähnliche Fälle genauso gut funktionieren(Äquivalenzklassen)

● Änderungen werden leichter möglich, weil sichergestellt wird,dass die bestehende Funktionalität nicht kaputt geht

● Tests sind die aktuellste Dokumentation

● Jeder Test erzählt eine Geschichte über was passiert undwas zu erwarten ist.

Page 4: Good Tests Bad Tests

Böse Tests

● Fragile Tests: kleine Änderung in derImplementierung => viele Tests betroffen

● Redundante Tests => Balast

● Triviale Tests

● Unvollständige Tests => falsche Sicherheit

● Tests ohne Asserts

Page 5: Good Tests Bad Tests

No Assertions

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

Page 6: Good Tests Bad Tests

No Assertions(verbessert)

IResult result = format.execute();assertThat(result.size()).isEqualTo(3); 1Iterator iter = result.iterator();while (iter.hasNext()) { IResult r = (IResult) iter.next(); assertThat(r.getMessage()).contains("error"); 2}

Page 7: Good Tests Bad Tests

Get- Setter

public void testSetGetParam() throws Exception { String[] tests = {"a", "aaa", "---", "23121313", "", null};

for (int i = 0; i < tests.length; i++) { adapter.setParam(tests[i]); assertEquals(tests[i], adapter.getParam()); }}

Page 8: Good Tests Bad Tests

Happy Path

public class FizzBuzzTest { @Test public void testMultipleOfThreeAndFivePrintsFizzBuzz() { assertEquals("FizzBuzz", FizzBuzz.getResult(15)); }

@Test public void testMultipleOfThreeOnlyPrintsFizz() { assertEquals("Fizz", FizzBuzz.getResult(93)); }

Page 9: Good Tests Bad Tests

Happy Path(verbessert)

@RunWith(JUnitParamsRunner.class)public class FizzBuzzJUnitTest {

@Test @Parameters(value = {"15", "30", "75"}) public void testMultipleOfThreeAndFivePrintsFizzBuzz( int multipleOf3And5) { assertEquals("FizzBuzz", FizzBuzz.getResult(multipleOf3And5)); }

@Test @Parameters(value = {"9", "36", "81"}) public void testMultipleOfThreeOnlyPrintsFizz(...

@Test @Parameters(value = {"10", "55", "100"}) public void testMultipleOfFiveOnlyPrintsBuzz(...

@Test @Parameters(value = {"2", "16", "23", "47", "52", ... public void testInputOfEightPrintsTheNumber(...}

Page 10: Good Tests Bad Tests

Not Enough Testing

@Testpublic class PagerTest {

private static final int PER_PAGE = 10;

public void shouldGiveOffsetZeroWhenOnZeroPage() { Pager pager = new Pager(PER_PAGE);

assertThat(pager.getOffset()).isEqualTo(0); }

public void shouldIncreaseOffsetWhenGoingToPageOne() { Pager pager = new Pager(PER_PAGE);

pager.goToNextPage();

assertThat(pager.getOffset()).isEqualTo(PER_PAGE); }}

Page 11: Good Tests Bad Tests

Not Enough Testing (verbessert)

Zero, One and Many

Page 12: Good Tests Bad Tests

Auskommentieren

//@Testpublic void testTeaserWithBildPlusMarker(){

String url = urlBuilder.setBaseUrl(HTTP_START_PATH + TEASERREIHE_BILDPLUS_MARKER_PATH.setView("module".build();

driver.get(url);

// TeaserreiheWebElement teaserReiheElement = getRootElement();BTOTeaserReihe_modulePO teaserReihePO =

new BTOTeaserReihe_modulePO(teaserReiheElement);List<Resource_teaserPO> teaserPOs =

teaserReihePO.getTeaserPOs();assertNotNull("Teaser-Page-Objekte fehlen", teaserPOs);assertEquals(1, teaserPOs.size());

}

(Aus bildcms JSP-Tests)

Page 13: Good Tests Bad Tests

Auskommentieren(verbessert)

@Test @Ignore //TODO momentan nicht testbar auf Testsystempublic void testTeaserWithBildPlusMarker(){

String url = urlBuilder.setBaseUrl(HTTP_START_PATH + TEASERREIHE_BILDPLUS_MARKER_PATH.setView("module".build();

driver.get(url);

// TeaserreiheWebElement teaserReiheElement = getRootElement();BTOTeaserReihe_modulePO teaserReihePO =

new BTOTeaserReihe_modulePO(teaserReiheElement);List<Resource_teaserPO> teaserPOs =

teaserReihePO.getTeaserPOs();assertNotNull("Teaser-Page-Objekte fehlen", teaserPOs);assertEquals(1, teaserPOs.size());

}

Page 14: Good Tests Bad Tests

Expecting Exceptions Anywhere

@Test(expected=IndexOutOfBoundsException.class)public void testMyList() { MyList<Integer> list = new MyList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(3); list.add(4); assertTrue(4 == list.get(4)); assertTrue(2 == list.get(1)); assertTrue(3 == list.get(2));

list.get(6);}

Page 15: Good Tests Bad Tests

Expecting Exceptions Anywhere(verbessert)

● Tests aufteilen (Split)● Exception-Test Lokalisieren

Page 16: Good Tests Bad Tests

Assertions should be Merciless

@Testpublic void shouldRemoveEmailsByState() { //given Email pending = createAndSaveEmail("pending","content pending", "[email protected]", Email.PENDING); Email failed = createAndSaveEmail("failed","content failed", "[email protected]", Email.FAILED); Email sent = createAndSaveEmail("sent","content sent", "[email protected]", Email.SENT);

//when emailDAO.removeByState(Email.FAILED);

//then assertThat(emailDAO.findAll()).excludes(failed);}

Page 17: Good Tests Bad Tests

Assertions should be Merciless(verbessert)

assertThat(emailDAO.findAll(),contains(pending, sent))

Page 18: Good Tests Bad Tests

Is Mockito Working Fine?

@Testpublic void testFormUpdate() { // given Form f = Mockito.mock(Form.class); Mockito.when( f.isUpdateAllowed()).thenReturn(true);

// when boolean result = f.isUpdateAllowed();

// then assertTrue(result);}

Page 19: Good Tests Bad Tests

@Testpublic void will_getChangSecurityQuestRgtAndDetails_if_AdvUserhasRuleId25(){ User user = createUser(userId); user.setAdvanced(true); PasswordRuleDto passwordRuleDto = new PasswordRuleDto(); passwordRuleDto.setPasswordRuleId(rulId25); List<PasswordRuleDto> passwordRules = new ArrayList<PasswordRuleDto>(); passwordRules.add(passwordRuleDto); given(currentUser.getUser()).thenReturn(user); given(userDAO.readByPrimaryKey(userId)).thenReturn(user); given(passwordBean.getPasswordRules()).thenReturn(passwordRules); UserSecurityQuestionDto dto = userChangeSecurityQuestionBean .getChangSecurityQuestionRgtAndDetails(); assertNotNull(dto.getEmail()); assertNotNull(dto.getFirstName()); assertNotNull(dto.getLastName()); assertEquals(dto.isChangeSecurityQuestion(), true);}

Why formatting helps

Page 20: Good Tests Bad Tests

@Testpublic void will_getChangSecurityQuestRgtAndDetails_if_AdvUserhasRuleId25(){ // given User user = createUser(userId); user.setAdvanced(true); PasswordRuleDto passwordRuleDto = new PasswordRuleDto();

passwordRuleDto.setPasswordRuleId(rulId25); List<PasswordRuleDto> passwordRules = new ArrayList<PasswordRuleDto>(); passwordRules.add(passwordRuleDto);

given(currentUser.getUser()).willReturn(user); given(userDAO.readByPrimaryKey(userId)).willReturn(user); given(passwordBean.getPasswordRules()).willReturn(passwordRules);

// when UserSecurityQuestionDto dto = userChangeSecurityQuestionBean .getChangSecurityQuestionRgtAndDetails();

// then assertNotNull(dto.getEmail()); assertNotNull(dto.getFirstName()); assertNotNull(dto.getLastName()); assertEquals(dto.isChangeSecurityQuestion(), true);}

Why formatting helps(verbessert)

Page 21: Good Tests Bad Tests

When a Test Name LiesShould is Better than Test

public void testInsertNewValues() { //given //when reportRepository.updateReport(ReportColumn.DATE, ReportColumn.PLACE, reportMap(BigDecimal.TEN)); reportRepository.updateReport(ReportColumn.DATE, ReportColumn.PLACE, reportMap(new BigDecimal("5")));

//then assertThat(reportRepository .getCount(ReportColumn.DATE, ReportColumn.PLACE)) .isEqualTo(1);}

Page 22: Good Tests Bad Tests

When a Test Name LiesShould is Better than Test

(korrigiert)public void shouldOverrideOldReportWithNewValues() { //given //when reportRepository.updateReport(ReportColumn.DATE, ReportColumn.PLACE, reportMap(BigDecimal.TEN)); reportRepository.updateReport(ReportColumn.DATE, ReportColumn.PLACE, reportMap(new BigDecimal("5")));

//then assertThat(reportRepository .getCount(ReportColumn.DATE, ReportColumn.PLACE)) .isEqualTo(1);}