SlideShare a Scribd company logo
Russell Gold
Any fool can write code that a
computer can understand. Good
programmers write code that humans
can understand.
- Martin Fowler
What’s wrong with this test?
@Test
public void testRead() throws Exception {
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(instream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(instream, Mockito.times(1)).close();
Mockito.verify(eofwatcher).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
}
(from the open-source project HttpClient)
Value of Unit Tests
Prevent Regression
Drive Development Facilitate Refactoring
Document Functionality
Strive for Clean Code
if ((getDate().year – dob.year > 62 || (getDate().year – dob.year == 62
&& getDate().month > dob.month)) && early)
payment = getEarlyPay();
else if ((getDate().year – dob.year > 65 || (getDate().year – dob.year == 65
&& getDate().month >= dob.month)) && !early)
payment = getRegPay();
else
payment = 0;
Duplication
Strive for Clean Code
if (getAgeInYears() >= 62 && early)
payment = getEarlyPay();
else if (getAgeInYears() >= 65 && !early)
payment = getRegPay();
else
payment = 0;
int getAgeInYears() {
int age = getDate().year – dob.year;
if (getDate().month >= dob.month) age++;
return age;
}
Magic
numbers
Strive for Clean Code
final static int EARLY_RETIREMENT_AGE = 62;
final static int REGULAR_RETIREMENT_AGE = 65;
if (getAgeInYears() >= EARLY_RETIREMENT_AGE && early)
payment = getEarlyPay();
else if (getAgeInYears() >= REGULAR_RETIREMENT_AGE && !early)
payment = getRegPay();
else
payment = 0; Complex conditional
Strive for Clean Code
final static int EARLY_RETIREMENT_AGE = 62;
final static int REGULAR_RETIREMENT_AGE = 65;
if (isCollectingEarlyRetirement())
payment = getEarlyPay();
else if (isCollectingRegularRetirement())
payment = getRegPay();
else
payment = 0;
boolean isCollectingEarlyRetirement() {
return early && getAgeInYears() >= EARLY_RETIREMENT_AGE);
}
Ambiguous
names
Strive for Clean Code
final static int EARLY_RETIREMENT_AGE = 62;
final static int REGULAR_RETIREMENT_AGE = 65;
if (isCollectingEarlyRetirement())
payment = getEarlyRetirementPayment();
else if (isCollectingRegularRetirement())
payment = getRegularRetirementPayment();
else
payment = 0;
boolean isCollectingEarlyRetirement() {
return electedEarlyRetirement && getAgeInYears() >= EARLY_RETIREMENT_AGE);
}
Unit Tests are Code
 Choose good method names
 Keep methods short and coherent
 Avoid magic numbers
 Avoid long argument lists
 Avoid duplication
Test One Thing Per Test
@Test
public void afterCellAdded_boardIsAtLeast10x10() {
Board board = new Board();
board.addCell(0, 0);
assertThat(board.getHeight(), is(greaterThan(10));
assertThat(board.getWidth(), is(greaterThan(10));
}
Name describes exactly what is being tested
Set up (could be part of test class setup)
Operation to test
Validation
Hamcrest Library
assertThat(number, both(greaterThan(10)).and(LessThan(30)));
assertThat(array, is(emptyArray());
assertThat(collection, hasItems(1, 4, 7));
assertThat(map, hasKey("color")
assertThat(javaBean, hasProperty("age"));
What’s wrong with this test?
@Test
public void testRead() throws Exception {
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(instream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(instream, Mockito.times(1)).close();
Mockito.verify(eofwatcher).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
}
@Test
public void testRead() throws Exception {
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(instream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(instream, Mockito.times(1)).close();
Mockito.verify(eofwatcher).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
}
Ambiguous
Sequence of cases
Magic numbers
Confusing Names
EofSensorInputStream
getWatcher()
getWrappedStream()
EofSensorWatcher
InputStream
eofwatcher
instream
Class being tested has two
component classes
wrappedStream
watcher
eofstream
Step 1: fix names
@Test
public void testRead() throws Exception {
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(instream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(instream, Mockito.times(1)).close();
Mockito.verify(eofwatcher).eofDetected(instream);
Assert.assertEquals(-1, eofstream.read());
}
Step 1: fix names
@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(-1, eofstream.read());
}
Step 2: magic numbers
@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(-1, eofstream.read());
}
Step 2: magic numbers
@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(0, -1);
Assert.assertEquals(0, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(-1, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(-1, eofstream.read());
}
Step 2: magic numbers
@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
}
Step 3: What’s being
tested?@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readReturnsNextByte() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readReturnsNextByte() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
Assert.assertEquals(DATA_VALUE, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
Assert.assertEquals(DATA_VALUE, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
assertThat(eofstream.read(), is(DATA_VALUE));
}
Step 4: Separate the Tests
@Test
public void testRead() throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNotNull(eofstream.getWrappedStream());
Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
Assert.assertNull(eofstream.getWrappedStream());
Mockito.verify(wrappedStream, Mockito.times(1)).close();
Mockito.verify(watcher).eofDetected(wrappedStream);
Assert.assertEquals(EOF, eofstream.read());
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readDoesNotCloseStream () throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
}
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
assertThat(eofstream.read(), is(DATA_VALUE));
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readDoesNotCloseStream () throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
Assert.assertEquals(DATA_VALUE, eofstream.read());
Assert.assertFalse(eofstream.isSelfClosed());
}
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
assertThat(eofstream.read(), is(DATA_VALUE));
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readDoesNotCloseStream () throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
eofstream.read();
Assert.assertFalse(eofstream.isSelfClosed());
}
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
assertThat(eofstream.read(), is(DATA_VALUE));
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readDoesNotCloseStream () throws Exception {
Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE);
Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF);
eofstream.read();
Assert.assertFalse(eofstream.isSelfClosed());
}
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
assertThat(eofstream.read(), is(DATA_VALUE));
}
Step 4: Separate the Tests
@Test
public void whenNotAtEOF_readDoesNotCloseStream () throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
eofstream.read();
Assert.assertFalse(eofstream.isSelfClosed());
}
@Test
public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
assertThat(eofstream.read(), is(DATA_VALUE));
}
@Test
public void afterSuccessfulRead_haveOriginalWrappedStream() throws Exception {
wrappedStream.returnOnRead(DATA_VALUE);
eofstream.read();
assertThat(eofstream.getWrappedStream(), sameInstance((InputStream) wrappedStream));
}
@Test
public void whenNoData_readReturnsEOF() throws Exception {
assertThat(eofstream.read(), is(EOF));
}
@Test
public void afterEofRead_streamIsNotSelfClosed() throws Exception {
eofstream.read();
assertFalse(eofstream.isSelfClosed());
}
@Test
public void afterEofRead_wrappedStreamIsNull() throws Exception {
eofstream.read();
assertThat(eofstream.getWrappedStream(), nullValue());
}
@Test
public void afterEofRead_wrappedStreamIsClosed() throws Exception {
eofstream.read();
assertTrue(wrappedStream.isClosed());
}
@Test
public void afterEofRead_nextReadReturnsEOF() throws Exception {
eofstream.read();
assertThat(eofstream.read(), is(EOF));
}
Tests Document Behavior
whenNotAtEOF_readReturnsNextByteFromWrappedStream
whenNotAtEOF_readDoesNotCloseStream
afterSuccessfulRead_haveOriginalWrappedStream
whenNoData_readReturnsEOF
afterEofRead_streamIsNotSelfClosed
afterEofRead_wrappedStreamIsNull
afterEofRead_wrappedStreamIsClosed
afterEofRead_nextReadReturnsEOF
Unit Tests are Executable Documentation
 Keep the tests clean
 Test one thing per test
 Use descriptive names
Q&A

More Related Content

What's hot

Unit testing concurrent code
Unit testing concurrent codeUnit testing concurrent code
Unit testing concurrent code
Rafael Winterhalter
 
Smarter Testing With Spock
Smarter Testing With SpockSmarter Testing With Spock
Smarter Testing With Spock
IT Weekend
 
Bdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteBdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infinite
Giordano Scalzo
 
Spock framework
Spock frameworkSpock framework
Spock framework
Djair Carvalho
 
About java
About javaAbout java
About java
Jay Xu
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
julien.ponge
 
Java 7 LavaJUG
Java 7 LavaJUGJava 7 LavaJUG
Java 7 LavaJUG
julien.ponge
 
Google guava
Google guavaGoogle guava
Simple API for XML
Simple API for XMLSimple API for XML
Simple API for XML
guest2556de
 
Test-driven Development for TYPO3
Test-driven Development for TYPO3Test-driven Development for TYPO3
Test-driven Development for TYPO3
Oliver Klee
 
JBoss Drools
JBoss DroolsJBoss Drools
JBoss Drools
Victor_Cr
 
Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113
SOAT
 
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and Prosper
Ken Kousen
 
soft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coin
soft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coinsoft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coin
soft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coin
soft-shake.ch
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
Daniel Kolman
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Pavlo Baron
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
Tomek Kaczanowski
 
GeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsGeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good Tests
Tomek Kaczanowski
 
Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good Tests
Tomek Kaczanowski
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
julien.ponge
 

What's hot (20)

Unit testing concurrent code
Unit testing concurrent codeUnit testing concurrent code
Unit testing concurrent code
 
Smarter Testing With Spock
Smarter Testing With SpockSmarter Testing With Spock
Smarter Testing With Spock
 
Bdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteBdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infinite
 
Spock framework
Spock frameworkSpock framework
Spock framework
 
About java
About javaAbout java
About java
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
 
Java 7 LavaJUG
Java 7 LavaJUGJava 7 LavaJUG
Java 7 LavaJUG
 
Google guava
Google guavaGoogle guava
Google guava
 
Simple API for XML
Simple API for XMLSimple API for XML
Simple API for XML
 
Test-driven Development for TYPO3
Test-driven Development for TYPO3Test-driven Development for TYPO3
Test-driven Development for TYPO3
 
JBoss Drools
JBoss DroolsJBoss Drools
JBoss Drools
 
Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113
 
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and Prosper
 
soft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coin
soft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coinsoft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coin
soft-shake.ch - Java SE 7: The Fork/Join Framework and Project Coin
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
GeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good TestsGeeCON 2012 Bad Tests, Good Tests
GeeCON 2012 Bad Tests, Good Tests
 
Confitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good TestsConfitura 2012 Bad Tests, Good Tests
Confitura 2012 Bad Tests, Good Tests
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
 

Similar to Executable documentation

Unit testing with PHPUnit
Unit testing with PHPUnitUnit testing with PHPUnit
Unit testing with PHPUnit
ferca_sl
 
J unit스터디슬라이드
J unit스터디슬라이드J unit스터디슬라이드
J unit스터디슬라이드
ksain
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unit
liminescence
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean tests
Danylenko Max
 
Shipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLabShipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLab
Dobromir Nikolov
 
JUnit Pioneer
JUnit PioneerJUnit Pioneer
JUnit Pioneer
Scott Leberknight
 
Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent code
Dror Helper
 
JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
John Ferguson Smart Limited
 
Next Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingNext Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized Testing
Tao Xie
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
jeresig
 
Unit testing with Easymock
Unit testing with EasymockUnit testing with Easymock
Unit testing with Easymock
Ürgo Ringo
 
GTAC 2014: What lurks in test suites?
GTAC 2014: What lurks in test suites?GTAC 2014: What lurks in test suites?
GTAC 2014: What lurks in test suites?
Patrick Lam
 
Mockito intro
Mockito introMockito intro
Mockito intro
Cristian R. Silva
 
Mockito intro
Mockito introMockito intro
Mockito intro
Jonathan Holloway
 
Resilience mit Hystrix
Resilience mit HystrixResilience mit Hystrix
Resilience mit Hystrix
Java Usergroup Berlin-Brandenburg
 
Java best practices
Java best practicesJava best practices
Java best practices
Ray Toal
 
jUnit
jUnitjUnit
jUnit
sundar22in
 
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, MelonUnit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
beITconference
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
Anton Arhipov
 
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Programming Java - Lection 07 - Puzzlers - Lavrentyev FedorProgramming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Fedor Lavrentyev
 

Similar to Executable documentation (20)

Unit testing with PHPUnit
Unit testing with PHPUnitUnit testing with PHPUnit
Unit testing with PHPUnit
 
J unit스터디슬라이드
J unit스터디슬라이드J unit스터디슬라이드
J unit스터디슬라이드
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unit
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean tests
 
Shipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLabShipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLab
 
JUnit Pioneer
JUnit PioneerJUnit Pioneer
JUnit Pioneer
 
Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent code
 
JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
 
Next Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingNext Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized Testing
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
Unit testing with Easymock
Unit testing with EasymockUnit testing with Easymock
Unit testing with Easymock
 
GTAC 2014: What lurks in test suites?
GTAC 2014: What lurks in test suites?GTAC 2014: What lurks in test suites?
GTAC 2014: What lurks in test suites?
 
Mockito intro
Mockito introMockito intro
Mockito intro
 
Mockito intro
Mockito introMockito intro
Mockito intro
 
Resilience mit Hystrix
Resilience mit HystrixResilience mit Hystrix
Resilience mit Hystrix
 
Java best practices
Java best practicesJava best practices
Java best practices
 
jUnit
jUnitjUnit
jUnit
 
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, MelonUnit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
 
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Programming Java - Lection 07 - Puzzlers - Lavrentyev FedorProgramming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
Programming Java - Lection 07 - Puzzlers - Lavrentyev Fedor
 

Recently uploaded

Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
Sven Peters
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
Bert Jan Schrijver
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
Alina Yurenko
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
Alberto Brandolini
 
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdfBaha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid
 
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CDKuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
rodomar2
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
Marcin Chrost
 
What’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete RoadmapWhat’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete Roadmap
Envertis Software Solutions
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
dakas1
 
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptxMigration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
ervikas4
 
UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
Peter Muessig
 
Kubernetes at Scale: Going Multi-Cluster with Istio
Kubernetes at Scale:  Going Multi-Cluster  with IstioKubernetes at Scale:  Going Multi-Cluster  with Istio
Kubernetes at Scale: Going Multi-Cluster with Istio
Severalnines
 
Project Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdfProject Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdf
Karya Keeper
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
Hornet Dynamics
 
The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024
Yara Milbes
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
XfilesPro
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
ppt on the brain chip neuralink.pptx
ppt  on   the brain  chip neuralink.pptxppt  on   the brain  chip neuralink.pptx
ppt on the brain chip neuralink.pptx
Reetu63
 
14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision
ShulagnaSarkar2
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 

Recently uploaded (20)

Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
 
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdfBaha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
 
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CDKuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
 
What’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete RoadmapWhat’s New in Odoo 17 – A Complete Roadmap
What’s New in Odoo 17 – A Complete Roadmap
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
 
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptxMigration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
 
UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
 
Kubernetes at Scale: Going Multi-Cluster with Istio
Kubernetes at Scale:  Going Multi-Cluster  with IstioKubernetes at Scale:  Going Multi-Cluster  with Istio
Kubernetes at Scale: Going Multi-Cluster with Istio
 
Project Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdfProject Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdf
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
 
The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024The Rising Future of CPaaS in the Middle East 2024
The Rising Future of CPaaS in the Middle East 2024
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
ppt on the brain chip neuralink.pptx
ppt  on   the brain  chip neuralink.pptxppt  on   the brain  chip neuralink.pptx
ppt on the brain chip neuralink.pptx
 
14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision14 th Edition of International conference on computer vision
14 th Edition of International conference on computer vision
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 

Executable documentation

  • 2. Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler
  • 3. What’s wrong with this test? @Test public void testRead() throws Exception { Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(instream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(instream, Mockito.times(1)).close(); Mockito.verify(eofwatcher).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); } (from the open-source project HttpClient)
  • 4. Value of Unit Tests Prevent Regression Drive Development Facilitate Refactoring Document Functionality
  • 5. Strive for Clean Code if ((getDate().year – dob.year > 62 || (getDate().year – dob.year == 62 && getDate().month > dob.month)) && early) payment = getEarlyPay(); else if ((getDate().year – dob.year > 65 || (getDate().year – dob.year == 65 && getDate().month >= dob.month)) && !early) payment = getRegPay(); else payment = 0; Duplication
  • 6. Strive for Clean Code if (getAgeInYears() >= 62 && early) payment = getEarlyPay(); else if (getAgeInYears() >= 65 && !early) payment = getRegPay(); else payment = 0; int getAgeInYears() { int age = getDate().year – dob.year; if (getDate().month >= dob.month) age++; return age; } Magic numbers
  • 7. Strive for Clean Code final static int EARLY_RETIREMENT_AGE = 62; final static int REGULAR_RETIREMENT_AGE = 65; if (getAgeInYears() >= EARLY_RETIREMENT_AGE && early) payment = getEarlyPay(); else if (getAgeInYears() >= REGULAR_RETIREMENT_AGE && !early) payment = getRegPay(); else payment = 0; Complex conditional
  • 8. Strive for Clean Code final static int EARLY_RETIREMENT_AGE = 62; final static int REGULAR_RETIREMENT_AGE = 65; if (isCollectingEarlyRetirement()) payment = getEarlyPay(); else if (isCollectingRegularRetirement()) payment = getRegPay(); else payment = 0; boolean isCollectingEarlyRetirement() { return early && getAgeInYears() >= EARLY_RETIREMENT_AGE); } Ambiguous names
  • 9. Strive for Clean Code final static int EARLY_RETIREMENT_AGE = 62; final static int REGULAR_RETIREMENT_AGE = 65; if (isCollectingEarlyRetirement()) payment = getEarlyRetirementPayment(); else if (isCollectingRegularRetirement()) payment = getRegularRetirementPayment(); else payment = 0; boolean isCollectingEarlyRetirement() { return electedEarlyRetirement && getAgeInYears() >= EARLY_RETIREMENT_AGE); }
  • 10. Unit Tests are Code  Choose good method names  Keep methods short and coherent  Avoid magic numbers  Avoid long argument lists  Avoid duplication
  • 11. Test One Thing Per Test @Test public void afterCellAdded_boardIsAtLeast10x10() { Board board = new Board(); board.addCell(0, 0); assertThat(board.getHeight(), is(greaterThan(10)); assertThat(board.getWidth(), is(greaterThan(10)); } Name describes exactly what is being tested Set up (could be part of test class setup) Operation to test Validation
  • 12. Hamcrest Library assertThat(number, both(greaterThan(10)).and(LessThan(30))); assertThat(array, is(emptyArray()); assertThat(collection, hasItems(1, 4, 7)); assertThat(map, hasKey("color") assertThat(javaBean, hasProperty("age"));
  • 13. What’s wrong with this test? @Test public void testRead() throws Exception { Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(instream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(instream, Mockito.times(1)).close(); Mockito.verify(eofwatcher).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); }
  • 14. @Test public void testRead() throws Exception { Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(instream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(instream, Mockito.times(1)).close(); Mockito.verify(eofwatcher).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); } Ambiguous Sequence of cases Magic numbers Confusing Names
  • 16. Step 1: fix names @Test public void testRead() throws Exception { Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(instream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(instream, Mockito.times(1)).close(); Mockito.verify(eofwatcher).eofDetected(instream); Assert.assertEquals(-1, eofstream.read()); }
  • 17. Step 1: fix names @Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(-1, eofstream.read()); }
  • 18. Step 2: magic numbers @Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(-1, eofstream.read()); }
  • 19. Step 2: magic numbers @Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(0, -1); Assert.assertEquals(0, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(-1, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(-1, eofstream.read()); }
  • 20. Step 2: magic numbers @Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); }
  • 21. Step 3: What’s being tested?@Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); }
  • 22. Step 4: Separate the Tests @Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); }
  • 23. Step 4: Separate the Tests @Test public void whenNotAtEOF_readReturnsNextByte() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); }
  • 24. Step 4: Separate the Tests @Test public void whenNotAtEOF_readReturnsNextByte() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); }
  • 25. Step 4: Separate the Tests @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); Assert.assertEquals(DATA_VALUE, eofstream.read()); }
  • 26. Step 4: Separate the Tests @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); Assert.assertEquals(DATA_VALUE, eofstream.read()); }
  • 27. Step 4: Separate the Tests @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); assertThat(eofstream.read(), is(DATA_VALUE)); }
  • 28. Step 4: Separate the Tests @Test public void testRead() throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNotNull(eofstream.getWrappedStream()); Mockito.verify(watcher, Mockito.never()).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); Assert.assertNull(eofstream.getWrappedStream()); Mockito.verify(wrappedStream, Mockito.times(1)).close(); Mockito.verify(watcher).eofDetected(wrappedStream); Assert.assertEquals(EOF, eofstream.read()); }
  • 29. Step 4: Separate the Tests @Test public void whenNotAtEOF_readDoesNotCloseStream () throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); } @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); assertThat(eofstream.read(), is(DATA_VALUE)); }
  • 30. Step 4: Separate the Tests @Test public void whenNotAtEOF_readDoesNotCloseStream () throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); Assert.assertEquals(DATA_VALUE, eofstream.read()); Assert.assertFalse(eofstream.isSelfClosed()); } @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); assertThat(eofstream.read(), is(DATA_VALUE)); }
  • 31. Step 4: Separate the Tests @Test public void whenNotAtEOF_readDoesNotCloseStream () throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); eofstream.read(); Assert.assertFalse(eofstream.isSelfClosed()); } @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); assertThat(eofstream.read(), is(DATA_VALUE)); }
  • 32. Step 4: Separate the Tests @Test public void whenNotAtEOF_readDoesNotCloseStream () throws Exception { Mockito.when(watcher.eofDetected(Mockito.<InputStream>any())).thenReturn(Boolean.TRUE); Mockito.when(wrappedStream.read()).thenReturn(DATA_VALUE, EOF); eofstream.read(); Assert.assertFalse(eofstream.isSelfClosed()); } @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); assertThat(eofstream.read(), is(DATA_VALUE)); }
  • 33. Step 4: Separate the Tests @Test public void whenNotAtEOF_readDoesNotCloseStream () throws Exception { wrappedStream.returnOnRead(DATA_VALUE); eofstream.read(); Assert.assertFalse(eofstream.isSelfClosed()); } @Test public void whenNotAtEOF_readReturnsNextByteFromWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); assertThat(eofstream.read(), is(DATA_VALUE)); }
  • 34. @Test public void afterSuccessfulRead_haveOriginalWrappedStream() throws Exception { wrappedStream.returnOnRead(DATA_VALUE); eofstream.read(); assertThat(eofstream.getWrappedStream(), sameInstance((InputStream) wrappedStream)); } @Test public void whenNoData_readReturnsEOF() throws Exception { assertThat(eofstream.read(), is(EOF)); } @Test public void afterEofRead_streamIsNotSelfClosed() throws Exception { eofstream.read(); assertFalse(eofstream.isSelfClosed()); }
  • 35. @Test public void afterEofRead_wrappedStreamIsNull() throws Exception { eofstream.read(); assertThat(eofstream.getWrappedStream(), nullValue()); } @Test public void afterEofRead_wrappedStreamIsClosed() throws Exception { eofstream.read(); assertTrue(wrappedStream.isClosed()); } @Test public void afterEofRead_nextReadReturnsEOF() throws Exception { eofstream.read(); assertThat(eofstream.read(), is(EOF)); }
  • 37. Unit Tests are Executable Documentation  Keep the tests clean  Test one thing per test  Use descriptive names
  • 38. Q&A