SlideShare a Scribd company logo
1 of 38
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

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
 
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
 
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
 
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
 
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
 
Unit testing with Easymock
Unit testing with EasymockUnit testing with Easymock
Unit testing with Easymock
Ürgo Ringo
 
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
 

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

Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 

Recently uploaded (20)

WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 

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