SlideShare a Scribd company logo
1 of 47
Download to read offline
Unbearable Test Smells
Steven Mak
steven@odd-e.com
www.odd-e.com
twitter: stevenmak
1
Monday, 15 November 2010
Who am I?
2
Name: Steven Mak
Agile Coach at Odd-e
Lives in Hong Kong
Agile/Scrum, TDD Coaching
I love coding - Java, C/C++,
PHP, Perl, C#, VB, and some
weird languages
Monday, 15 November 2010
Copy and Paste Code
Long test codes are copied and pasted somewhere else with only a few
lines changing
3
Monday, 15 November 2010
DRY
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
DonŹ¼t Repeat Yourself!
4
Monday, 15 November 2010
Not knowing the ļ¬xtures
Some initialisation and clean up codes that are repeated in each tests...
5
Monday, 15 November 2010
What is ļ¬xture?
TEST_GROUP (TEST_thisObject)
{
void setup() {
}
void teardown() {
}
};
6
Monday, 15 November 2010
Duplication causing fragile
tests
Where is the duplication?
EXPECT_LOG(ā€œABC errorā€);
7
Monday, 15 November 2010
Duplication causing fragile
tests
Where is the duplication?
EXPECT_LOG(ā€œABC errorā€);
So there is a line in code that
prints this log message
8
Monday, 15 November 2010
Duplication causing fragile
tests
Put it under centralise header ļ¬le:
#deļ¬ne ABC_ERROR_WITH_EC ā€œABC errorā€
The test will then look like:
EXPECT_LOG(ABC_ERROR);
9
Monday, 15 November 2010
Over-Optimism?
Tests that forgot to cover exceptional cases or just covered the easiest
condition
if (aaa() || bbb() || ccc() {
...
} else {
...
}
10
Monday, 15 November 2010
Tests donŹ¼t have assertions
TEST(TEST_GROUP, TEST_THIS)
{
runThisFunctionLaLaLa();
}
11
Monday, 15 November 2010
12
What does it mean by 80% Unit
Test Coverage?
Monday, 15 November 2010
Why xUnits donŹ¼t have
CHECK_NOT_EQUAL?
What is the problem with:
CHECK(TRUE, xxx != 3);
13
Monday, 15 November 2010
Why xUnits donŹ¼t have
CHECK_NOT_EQUAL?
What is the problem with:
CHECK(TRUE, xxx != 3);
Is there any good reason why you
cannot know the output value?
So, tell me what it is then. 14
Monday, 15 November 2010
OK, ļ¬ne, so I use CHECK with a
speciļ¬c output value, what now?
What is the problem with:
CHECK(TRUE, xxx == 4);
15
Monday, 15 November 2010
OK, ļ¬ne, so I use CHECK with a
speciļ¬c output value, what now?
What is the problem with:
CHECK(TRUE, xxx == 4);
In most xUnits, we have
LONGS_EQUAL telling you the actual
value when it goes wrong instead of a
ā€œfalseā€
16
Monday, 15 November 2010
17
Do you know your xUnit harness?
Monday, 15 November 2010
Further example

 try {

 
 readConļ¬gurationFile();

 
 assertTrue(true);

 } catch (IOException e) {

 
 assertTrue(false);

 
 e.printStackTrace();

 }
These are the places you know your
team does not know the test harness.
18
Monday, 15 November 2010
19
Some xUnit harness
Java: JUnit
.Net: NUnit
C/C++: CppUTest
PHP: PHPUnit
Monday, 15 November 2010
WhatŹ¼s wrong?
What is the problem with:
TEST(TEST_AIH, FAIL_BAD_PARAM)
20
Monday, 15 November 2010
Names donŹ¼t really tell
What is the problem with:
TEST(TEST_AIH, FAIL_BAD_PARAM)
Be more precise about how it
triggered the failure
21
Monday, 15 November 2010
What names tell us?
ā€¢ Who
- Name of the SUT class
- Name of the method or feature being exercised
ā€¢ Input
- Important characteristics of any input values
- Anything relevant about the state
ā€¢ Output
- The outputs expected
- The expected post-exercise state
22
Monday, 15 November 2010
Conditional Test Logic?
// verify Vancouver is in the list
actual = null;
i = ļ¬‚ightsFromCalgary.iterator();
while (i.hasNext()) {

 FlightDto ļ¬‚ightDto = (FlightDto) i.next();

 if (ļ¬‚ightDto.getFlightNumber().equals(

 
 expectedCalgaryToVan.getFlightNumber()))

 {

 
 actual = ļ¬‚ightDto;

 
 assertEquals("Flight from Calgary to Vancouver",

 
 
 expectedCalgaryToVan,

 
 
 ļ¬‚ightDto);

 
 break;

 }
}
23
Monday, 15 November 2010
Tests that crash 50% of the
time?!!
24
Monday, 15 November 2010
public void testFlightMileage_asKm2() throws Exception {

 // set up ļ¬xture

 // exercise constructor

 Flight newFlight = new Flight(validFlightNumber);

 // verify constructed object

 assertEquals(validFlightNumber, newFlight.number);

 assertEquals("", newFlight.airlineCode);

 assertNull(newFlight.airline);

 // set up mileage

 newFlight.setMileage(1122);

 // exercise mileage translator

 int actualKilometres = newFlight.getMileageAsKm();

 // verify results

 int expectedKilometres = 1810;

 assertEquals( expectedKilometres, actualKilometres);

 // now try it with a canceled ļ¬‚ight

 newFlight.cancel();

 try {

 
 newFlight.getMileageAsKm();

 
 fail("Expected exception");

 } catch (InvalidRequestException e) {

 
 assertEquals( "Cannot get cancelled ļ¬‚ight mileage",

 
 e.getMessage());

 }
}
25
Testing everything at a time
Monday, 15 November 2010
Testing everything at a time
public void testFlightMileage_asKm2() throws Exception {

 // set up ļ¬xture

 // exercise constructor

 Flight newFlight = new Flight(validFlightNumber);

 // verify constructed object

 assertEquals(validFlightNumber, newFlight.number);

 assertEquals("", newFlight.airlineCode);

 assertNull(newFlight.airline);

 // set up mileage

 newFlight.setMileage(1122);

 // exercise mileage translator

 int actualKilometres = newFlight.getMileageAsKm();

 // verify results

 int expectedKilometres = 1810;

 assertEquals( expectedKilometres, actualKilometres);

 // now try it with a canceled ļ¬‚ight

 newFlight.cancel();

 try {

 
 newFlight.getMileageAsKm();

 
 fail("Expected exception");

 } catch (InvalidRequestException e) {

 
 assertEquals( "Cannot get cancelled ļ¬‚ight mileage",

 
 e.getMessage());

 }
}
26
Comments as
deodorant
Monday, 15 November 2010
Testing everything at a time
public void testFlightMileage_asKm2() throws Exception {

 // set up ļ¬xture

 // exercise constructor

 Flight newFlight = new Flight(validFlightNumber);

 // verify constructed object

 assertEquals(validFlightNumber, newFlight.number);

 assertEquals("", newFlight.airlineCode);

 assertNull(newFlight.airline);

 // set up mileage

 newFlight.setMileage(1122);

 // exercise mileage translator

 int actualKilometres = newFlight.getMileageAsKm();

 // verify results

 int expectedKilometres = 1810;

 assertEquals( expectedKilometres, actualKilometres);

 // now try it with a canceled ļ¬‚ight

 newFlight.cancel();

 try {

 
 newFlight.getMileageAsKm();

 
 fail("Expected exception");

 } catch (InvalidRequestException e) {

 
 assertEquals( "Cannot get cancelled ļ¬‚ight mileage",

 
 e.getMessage());

 }
}
27
Duplications with
application logic?
Monday, 15 November 2010
Inappropriate dependencies
ā€¢ Test setup depending on other tests ļ¬les
ā€¢ A test ļ¬le depending on another test ļ¬le
ā€¢ Stub functions depending on other tests
extern int reg_ecx; // in the stub program
int reg_exc; // in SUT
28
Monday, 15 November 2010
What can we do?
29
Monday, 15 November 2010
Try: one test group per ļ¬le
But why canŹ¼t? is it because of... ?
30
Monday, 15 November 2010
Test initialisation hard to read
and shared among test groups
in the same test ļ¬le
ā€¢ Fixtures
ā€¢ Test Data Builder
ā€¢ Parameterised Creation
ā€¢ make-it-easy
31
Monday, 15 November 2010
Dont forget ļ¬xtures
TEST_GROUP (TEST_thisObject)
{

 void setup()

 {

 }

 void teardown()

 {

 }
};
32
Monday, 15 November 2010
Test Data Builder
eth_data_buf
->setControl(2)
->withParameterA(3)
->build();
33
Monday, 15 November 2010
Parameterised Creation
@Before
public void setUp() throws Exception {

 alice = new Person();

 alice.setId(1L);

 alice.setFirstname("Alice");

 alice.setLastname("Adams");

 alice.setSsn("111111");

 billy = new Person();

 billy.setId(2L);

 billy.setFirstname("Billy");

 billy.setLastname("Burke");

 billy.setSsn("222222");

 clark = new Person();

 clark.setId(3L);

 clark.setFirstname("Clark");

 clark.setLastname("Cable");

 clark.setSsn("333333");

 alice.isInLoveWith(billy);
}
34
Monday, 15 November 2010
Parameterised Creation
public class ParameterizedCreationMethodExample {

 private Person alice, billy, clark;

 @Before

 public void setUp() throws Exception {

 
 clark = createPerson("Clark", "Cable");

 
 billy = createPerson("Billy", "Burke");

 
 alice = createPerson("Alice", "Adams");

 
 alice.isInLoveWith(billy);

 }

 private Person createPerson(String firstName, String lastName) {

 
 Person person = new Person();

 
 person.setFirstname(firstName);

 
 person.setLastname(lastName);

 
 person.setId(UniqueNumber.next());

 
 person.setSsn(String.valueOf(UniqueNumber.next()));

 
 return person;

 }

 @Test

 public void aliceShouldAcceptWhenProposedToByBilly()

 
 throws Exception {

 
 billy.proposeTo(alice);

 
 assertTrue(alice.isEngagedWith(billy));

 }
}
35
Monday, 15 November 2010
make-it-easy
36
http://code.google.com/p/make-it-easy/
Maker<Apple> appleWith2Leaves = an(Apple, with(2, leaves));
Maker<Apple> ripeApple = appleWith2Leaves.but(with(ripeness, 0.9));
Maker<Apple> unripeApple = appleWith2Leaves.but(with(ripeness, 0.125));
Ā  Ā  Ā  Ā 
Apple apple1 = make(ripeApple);
Apple apple2 = make(unripeApple);
Ā  Ā  Ā  Ā 
Banana defaultBanana = make(a(Banana));
Banana straightBanana = make(a(Banana, with(curve, 0.0)));
Banana squishyBanana = make(a(Banana, with(ripeness, 1.0)));
Monday, 15 November 2010
Try: One assertion per test
37
Monday, 15 November 2010
Customised Assertions
#define CHECK_OBJ(a,b) CHECK_OBJ(a,b, __FILE__,__FILE__)
void CHECK_OBJ(struct* yourObj, struct* myObj, const char* file, int line)
{

 if (structs are not equal) {

 
 SimpleString errorMessage = StringFromFormat(

 
 
 ā€œMy struct: %d, %p, %sā€, myObj->d, myObj->p, myObj->s);

 
 FAIL_LOCATION(errorMessage.asCharString(), file, line);

 }
}
38
Monday, 15 November 2010
At least: One concept per test
39
Monday, 15 November 2010
Hamcrest
ā€¢ Framework for writing declarative match criteria
40http://code.google.com/p/hamcrest/
String s = "yes we have no bananas today";
Matcher<String> containsBananas = new StringContains("bananas");
Matcher<String> containsMangoes = new StringContains("mangoes");
assertTrue(containsBananas.matches(s));
assertFalse(containsMangoes.matches(s));
assertThat(s, containsString("bananas"));
assertThat(s, not(containsString("mangoes"));
Or even better
Monday, 15 November 2010
Meaningful Assertion Messages
41
ā€¢ DonŹ¼t repeat what the built-in test framework
outputs to the console (e.g. name of the test
method)
ā€¢ DonŹ¼t repeat what the test name explains
ā€¢ If you donŹ¼t have anything good to say, you donŹ¼t
have to say anything
ā€¢ Write what should have happened, or what failed
to happen, and possibly mention when it should
have happened
Monday, 15 November 2010
ItŹ¼s Design Smell!!!
42
Monday, 15 November 2010
Extra Constructor
43
public class LogFileMerge {

 private URL logFileA, logFileB;

 public LogFileMerge() {

 
 this(new URL("http://server1/system.log"),

 
 new URL("http://server2/system.log"));

 }

 LogFileMerge(URL a, URL b) {

 
 this.logFileA = a;

 
 this.logFileB = b;

 }
}
Monday, 15 November 2010
Test-Speciļ¬c SubClass
44
public class CreditCardProcessing {

 public boolean isValid(String cardnumber) {

 
 return validationCodeMatches(cardnumber)

 
 
 && cardIsActive(cardnumber);

 }

 protected boolean validationCodeMatches(String cardnumber) {

 
 // validation logic omitted for brevity...

 }

 protected boolean cardIsActive(String cardnumber) {

 
 // access to merchant system's web service

 
 // omitted for brevity...

 }
}
Monday, 15 November 2010
Still not testable?
45
ā€¢ Do you follow good design principles?
Monday, 15 November 2010
Thinking
46
Test code is not second class citizen
Good design principles apply:
ā€¢ Responsibility
ā€¢ Dependency
ā€¢ Low Coupling
ā€¢ High Cohesion
ā€¢ Indirection
ā€¢ Protected Variations
Watch out for organisational dysfunction!
Monday, 15 November 2010
References
ā€¢ Practical TDD and ATDD for Java Developers - Lasse Koskela
ā€¢ Growing OO Software, guided by tests - Steve Freeman
ā€¢ xUnit Test Patterns - Gerard Meszaros
47
Steven Mak
steven@odd-e.com
www.odd-e.com
twitter: stevenmak
Monday, 15 November 2010

More Related Content

What's hot

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
Ā 
Easy Button
Easy ButtonEasy Button
Easy Button
Adam Dale
Ā 
G*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³III
G*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³IIIG*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³III
G*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³III
Takuma Watabiki
Ā 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
Tomek Kaczanowski
Ā 

What's hot (20)

Introduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicoxIntroduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicox
Ā 
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
Ā 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
Ā 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
Ā 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!
Ā 
Using Reflections and Automatic Code Generation
Using Reflections and Automatic Code GenerationUsing Reflections and Automatic Code Generation
Using Reflections and Automatic Code Generation
Ā 
EcmaScript 6
EcmaScript 6 EcmaScript 6
EcmaScript 6
Ā 
0003 es5 ķ•µģ‹¬ ģ •ė¦¬
0003 es5 ķ•µģ‹¬ ģ •ė¦¬0003 es5 ķ•µģ‹¬ ģ •ė¦¬
0003 es5 ķ•µģ‹¬ ģ •ė¦¬
Ā 
Easy Button
Easy ButtonEasy Button
Easy Button
Ā 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
Ā 
TDC2016SP - Trilha .NET
TDC2016SP - Trilha .NETTDC2016SP - Trilha .NET
TDC2016SP - Trilha .NET
Ā 
JavaScript Survival Guide
JavaScript Survival GuideJavaScript Survival Guide
JavaScript Survival Guide
Ā 
G*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³III
G*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³IIIG*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³III
G*ć«ćŠć‘ć‚‹ć‚½ćƒ•ćƒˆć‚¦ć‚§ć‚¢ćƒ†ć‚¹ćƒˆćƒ»ć‚·ćƒ¼ć‚ŗćƒ³III
Ā 
Spock Testing Framework - The Next Generation
Spock Testing Framework - The Next GenerationSpock Testing Framework - The Next Generation
Spock Testing Framework - The Next Generation
Ā 
Redux for ReactJS Programmers
Redux for ReactJS ProgrammersRedux for ReactJS Programmers
Redux for ReactJS Programmers
Ā 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
Ā 
#JavaFX.forReal() - ElsassJUG
#JavaFX.forReal() - ElsassJUG#JavaFX.forReal() - ElsassJUG
#JavaFX.forReal() - ElsassJUG
Ā 
ES6 in Real Life
ES6 in Real LifeES6 in Real Life
ES6 in Real Life
Ā 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)
Ā 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
Ā 

Similar to Unbearable Test Code Smell

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
Ā 
Improving the java type system
Improving the java type systemImproving the java type system
Improving the java type system
JoĆ£o Loff
Ā 
Javascript: the important bits
Javascript: the important bitsJavascript: the important bits
Javascript: the important bits
Chris Saylor
Ā 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
Abed Bukhari
Ā 
C# labprograms
C# labprogramsC# labprograms
C# labprograms
Jafar Nesargi
Ā 

Similar to Unbearable Test Code Smell (20)

Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Ā 
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
Ā 
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
Ā 
Davide Cerbo - Kotlin: forse ĆØ la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse ĆØ la volta buona - Codemotion Milan 2017 Davide Cerbo - Kotlin: forse ĆØ la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse ĆØ la volta buona - Codemotion Milan 2017
Ā 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
Ā 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Know
Ā 
Dat testing - An introduction to Java and Android Testing
Dat testing - An introduction to Java and Android TestingDat testing - An introduction to Java and Android Testing
Dat testing - An introduction to Java and Android Testing
Ā 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
Ā 
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
JavaScript Iteration Protocols - Workshop NodeConf EU 2022JavaScript Iteration Protocols - Workshop NodeConf EU 2022
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
Ā 
Kotlin Generation
Kotlin GenerationKotlin Generation
Kotlin Generation
Ā 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
Ā 
Improving the java type system
Improving the java type systemImproving the java type system
Improving the java type system
Ā 
Javascript: the important bits
Javascript: the important bitsJavascript: the important bits
Javascript: the important bits
Ā 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
Ā 
Writing Good Tests
Writing Good TestsWriting Good Tests
Writing Good Tests
Ā 
Kotlin
KotlinKotlin
Kotlin
Ā 
C# labprograms
C# labprogramsC# labprograms
C# labprograms
Ā 
Cool JVM Tools to Help You Test
Cool JVM Tools to Help You TestCool JVM Tools to Help You Test
Cool JVM Tools to Help You Test
Ā 
Kotlin Overview (PT-BR)
Kotlin Overview (PT-BR)Kotlin Overview (PT-BR)
Kotlin Overview (PT-BR)
Ā 
Google guava
Google guavaGoogle guava
Google guava
Ā 

More from Steven Mak (11)

Continuous Security Testing
Continuous Security TestingContinuous Security Testing
Continuous Security Testing
Ā 
Quality comes free with open source testing tools
Quality comes free with open source testing toolsQuality comes free with open source testing tools
Quality comes free with open source testing tools
Ā 
Adopting technical practices 2013
Adopting technical practices 2013Adopting technical practices 2013
Adopting technical practices 2013
Ā 
100 doors kata solution
100 doors kata solution100 doors kata solution
100 doors kata solution
Ā 
Bossless companies
Bossless companiesBossless companies
Bossless companies
Ā 
Is this how you hate unit testing?
Is this how you hate unit testing?Is this how you hate unit testing?
Is this how you hate unit testing?
Ā 
Driving Quality with TDD
Driving Quality with TDDDriving Quality with TDD
Driving Quality with TDD
Ā 
Sustainable TDD
Sustainable TDDSustainable TDD
Sustainable TDD
Ā 
Introduction to Acceptance Test Driven Development
Introduction to Acceptance Test Driven DevelopmentIntroduction to Acceptance Test Driven Development
Introduction to Acceptance Test Driven Development
Ā 
Essential practices and thinking tools for Agile Adoption
Essential practices and thinking tools for Agile AdoptionEssential practices and thinking tools for Agile Adoption
Essential practices and thinking tools for Agile Adoption
Ā 
ATDD in Practice
ATDD in PracticeATDD in Practice
ATDD in Practice
Ā 

Recently uploaded

VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...
VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...
VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...
SUHANI PANDEY
Ā 
ab-initio-training basics and architecture
ab-initio-training basics and architectureab-initio-training basics and architecture
ab-initio-training basics and architecture
saipriyacoool
Ā 
āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men šŸ”dehradunšŸ” Escor...
āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men  šŸ”dehradunšŸ”   Escor...āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men  šŸ”dehradunšŸ”   Escor...
āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men šŸ”dehradunšŸ” Escor...
amitlee9823
Ā 
Peaches App development presentation deck
Peaches App development presentation deckPeaches App development presentation deck
Peaches App development presentation deck
tbatkhuu1
Ā 
āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men šŸ”BokarošŸ” Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men  šŸ”BokarošŸ”   Escorts S...āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men  šŸ”BokarošŸ”   Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men šŸ”BokarošŸ” Escorts S...
amitlee9823
Ā 
Editorial design Magazine design project.pdf
Editorial design Magazine design project.pdfEditorial design Magazine design project.pdf
Editorial design Magazine design project.pdf
tbatkhuu1
Ā 
āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men šŸ”jhansišŸ” Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men  šŸ”jhansišŸ”   Escorts S...āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men  šŸ”jhansišŸ”   Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men šŸ”jhansišŸ” Escorts S...
amitlee9823
Ā 
Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...
Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...
Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...
amitlee9823
Ā 
Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...
Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...
Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...
instagramfab782445
Ā 

Recently uploaded (20)

Hire šŸ’• 8617697112 Meerut Call Girls Service Call Girls Agency
Hire šŸ’• 8617697112 Meerut Call Girls Service Call Girls AgencyHire šŸ’• 8617697112 Meerut Call Girls Service Call Girls Agency
Hire šŸ’• 8617697112 Meerut Call Girls Service Call Girls Agency
Ā 
VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...
VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...
VIP Model Call Girls Kalyani Nagar ( Pune ) Call ON 8005736733 Starting From ...
Ā 
call girls in Vaishali (Ghaziabad) šŸ” >ą¼’8448380779 šŸ” genuine Escort Service šŸ”āœ”ļøāœ”ļø
call girls in Vaishali (Ghaziabad) šŸ” >ą¼’8448380779 šŸ” genuine Escort Service šŸ”āœ”ļøāœ”ļøcall girls in Vaishali (Ghaziabad) šŸ” >ą¼’8448380779 šŸ” genuine Escort Service šŸ”āœ”ļøāœ”ļø
call girls in Vaishali (Ghaziabad) šŸ” >ą¼’8448380779 šŸ” genuine Escort Service šŸ”āœ”ļøāœ”ļø
Ā 
ab-initio-training basics and architecture
ab-initio-training basics and architectureab-initio-training basics and architecture
ab-initio-training basics and architecture
Ā 
Sector 105, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 105, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 105, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 105, Noida Call girls :8448380779 Model Escorts | 100% verified
Ā 
High Profile Escorts Nerul WhatsApp +91-9930687706, Best Service
High Profile Escorts Nerul WhatsApp +91-9930687706, Best ServiceHigh Profile Escorts Nerul WhatsApp +91-9930687706, Best Service
High Profile Escorts Nerul WhatsApp +91-9930687706, Best Service
Ā 
The hottest UI and UX Design Trends 2024
The hottest UI and UX Design Trends 2024The hottest UI and UX Design Trends 2024
The hottest UI and UX Design Trends 2024
Ā 
āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men šŸ”dehradunšŸ” Escor...
āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men  šŸ”dehradunšŸ”   Escor...āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men  šŸ”dehradunšŸ”   Escor...
āž„šŸ” 7737669865 šŸ”ā–» dehradun Call-girls in Women Seeking Men šŸ”dehradunšŸ” Escor...
Ā 
Peaches App development presentation deck
Peaches App development presentation deckPeaches App development presentation deck
Peaches App development presentation deck
Ā 
Sweety Planet Packaging Design Process Book.pptx
Sweety Planet Packaging Design Process Book.pptxSweety Planet Packaging Design Process Book.pptx
Sweety Planet Packaging Design Process Book.pptx
Ā 
āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men šŸ”BokarošŸ” Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men  šŸ”BokarošŸ”   Escorts S...āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men  šŸ”BokarošŸ”   Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» Bokaro Call-girls in Women Seeking Men šŸ”BokarošŸ” Escorts S...
Ā 
Editorial design Magazine design project.pdf
Editorial design Magazine design project.pdfEditorial design Magazine design project.pdf
Editorial design Magazine design project.pdf
Ā 
āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men šŸ”jhansišŸ” Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men  šŸ”jhansišŸ”   Escorts S...āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men  šŸ”jhansišŸ”   Escorts S...
āž„šŸ” 7737669865 šŸ”ā–» jhansi Call-girls in Women Seeking Men šŸ”jhansišŸ” Escorts S...
Ā 
Jordan_Amanda_DMBS202404_PB1_2024-04.pdf
Jordan_Amanda_DMBS202404_PB1_2024-04.pdfJordan_Amanda_DMBS202404_PB1_2024-04.pdf
Jordan_Amanda_DMBS202404_PB1_2024-04.pdf
Ā 
šŸ’«āœ…jodhpur 24Ɨ7 BEST GENUINE PERSON LOW PRICE CALL GIRL SERVICE FULL SATISFACT...
šŸ’«āœ…jodhpur 24Ɨ7 BEST GENUINE PERSON LOW PRICE CALL GIRL SERVICE FULL SATISFACT...šŸ’«āœ…jodhpur 24Ɨ7 BEST GENUINE PERSON LOW PRICE CALL GIRL SERVICE FULL SATISFACT...
šŸ’«āœ…jodhpur 24Ɨ7 BEST GENUINE PERSON LOW PRICE CALL GIRL SERVICE FULL SATISFACT...
Ā 
Top Rated Pune Call Girls Koregaon Park āŸŸ 6297143586 āŸŸ Call Me For Genuine S...
Top Rated  Pune Call Girls Koregaon Park āŸŸ 6297143586 āŸŸ Call Me For Genuine S...Top Rated  Pune Call Girls Koregaon Park āŸŸ 6297143586 āŸŸ Call Me For Genuine S...
Top Rated Pune Call Girls Koregaon Park āŸŸ 6297143586 āŸŸ Call Me For Genuine S...
Ā 
WhatsApp Chat: šŸ“ž 8617697112 Call Girl Baran is experienced
WhatsApp Chat: šŸ“ž 8617697112 Call Girl Baran is experiencedWhatsApp Chat: šŸ“ž 8617697112 Call Girl Baran is experienced
WhatsApp Chat: šŸ“ž 8617697112 Call Girl Baran is experienced
Ā 
Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...
Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...
Jigani Call Girls Service: šŸ“ 7737669865 šŸ“ High Profile Model Escorts | Bangal...
Ā 
Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...
Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...
Abortion pill for sale in Muscat (+918761049707)) Get Cytotec Cash on deliver...
Ā 
Just Call Vip call girls Nagpur Escorts ā˜Žļø8617370543 Starting From 5K to 25K ...
Just Call Vip call girls Nagpur Escorts ā˜Žļø8617370543 Starting From 5K to 25K ...Just Call Vip call girls Nagpur Escorts ā˜Žļø8617370543 Starting From 5K to 25K ...
Just Call Vip call girls Nagpur Escorts ā˜Žļø8617370543 Starting From 5K to 25K ...
Ā 

Unbearable Test Code Smell

  • 1. Unbearable Test Smells Steven Mak steven@odd-e.com www.odd-e.com twitter: stevenmak 1 Monday, 15 November 2010
  • 2. Who am I? 2 Name: Steven Mak Agile Coach at Odd-e Lives in Hong Kong Agile/Scrum, TDD Coaching I love coding - Java, C/C++, PHP, Perl, C#, VB, and some weird languages Monday, 15 November 2010
  • 3. Copy and Paste Code Long test codes are copied and pasted somewhere else with only a few lines changing 3 Monday, 15 November 2010
  • 4. DRY DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! DonŹ¼t Repeat Yourself! 4 Monday, 15 November 2010
  • 5. Not knowing the ļ¬xtures Some initialisation and clean up codes that are repeated in each tests... 5 Monday, 15 November 2010
  • 6. What is ļ¬xture? TEST_GROUP (TEST_thisObject) { void setup() { } void teardown() { } }; 6 Monday, 15 November 2010
  • 7. Duplication causing fragile tests Where is the duplication? EXPECT_LOG(ā€œABC errorā€); 7 Monday, 15 November 2010
  • 8. Duplication causing fragile tests Where is the duplication? EXPECT_LOG(ā€œABC errorā€); So there is a line in code that prints this log message 8 Monday, 15 November 2010
  • 9. Duplication causing fragile tests Put it under centralise header ļ¬le: #deļ¬ne ABC_ERROR_WITH_EC ā€œABC errorā€ The test will then look like: EXPECT_LOG(ABC_ERROR); 9 Monday, 15 November 2010
  • 10. Over-Optimism? Tests that forgot to cover exceptional cases or just covered the easiest condition if (aaa() || bbb() || ccc() { ... } else { ... } 10 Monday, 15 November 2010
  • 11. Tests donŹ¼t have assertions TEST(TEST_GROUP, TEST_THIS) { runThisFunctionLaLaLa(); } 11 Monday, 15 November 2010
  • 12. 12 What does it mean by 80% Unit Test Coverage? Monday, 15 November 2010
  • 13. Why xUnits donŹ¼t have CHECK_NOT_EQUAL? What is the problem with: CHECK(TRUE, xxx != 3); 13 Monday, 15 November 2010
  • 14. Why xUnits donŹ¼t have CHECK_NOT_EQUAL? What is the problem with: CHECK(TRUE, xxx != 3); Is there any good reason why you cannot know the output value? So, tell me what it is then. 14 Monday, 15 November 2010
  • 15. OK, ļ¬ne, so I use CHECK with a speciļ¬c output value, what now? What is the problem with: CHECK(TRUE, xxx == 4); 15 Monday, 15 November 2010
  • 16. OK, ļ¬ne, so I use CHECK with a speciļ¬c output value, what now? What is the problem with: CHECK(TRUE, xxx == 4); In most xUnits, we have LONGS_EQUAL telling you the actual value when it goes wrong instead of a ā€œfalseā€ 16 Monday, 15 November 2010
  • 17. 17 Do you know your xUnit harness? Monday, 15 November 2010
  • 18. Further example try { readConļ¬gurationFile(); assertTrue(true); } catch (IOException e) { assertTrue(false); e.printStackTrace(); } These are the places you know your team does not know the test harness. 18 Monday, 15 November 2010
  • 19. 19 Some xUnit harness Java: JUnit .Net: NUnit C/C++: CppUTest PHP: PHPUnit Monday, 15 November 2010
  • 20. WhatŹ¼s wrong? What is the problem with: TEST(TEST_AIH, FAIL_BAD_PARAM) 20 Monday, 15 November 2010
  • 21. Names donŹ¼t really tell What is the problem with: TEST(TEST_AIH, FAIL_BAD_PARAM) Be more precise about how it triggered the failure 21 Monday, 15 November 2010
  • 22. What names tell us? ā€¢ Who - Name of the SUT class - Name of the method or feature being exercised ā€¢ Input - Important characteristics of any input values - Anything relevant about the state ā€¢ Output - The outputs expected - The expected post-exercise state 22 Monday, 15 November 2010
  • 23. Conditional Test Logic? // verify Vancouver is in the list actual = null; i = ļ¬‚ightsFromCalgary.iterator(); while (i.hasNext()) { FlightDto ļ¬‚ightDto = (FlightDto) i.next(); if (ļ¬‚ightDto.getFlightNumber().equals( expectedCalgaryToVan.getFlightNumber())) { actual = ļ¬‚ightDto; assertEquals("Flight from Calgary to Vancouver", expectedCalgaryToVan, ļ¬‚ightDto); break; } } 23 Monday, 15 November 2010
  • 24. Tests that crash 50% of the time?!! 24 Monday, 15 November 2010
  • 25. public void testFlightMileage_asKm2() throws Exception { // set up ļ¬xture // exercise constructor Flight newFlight = new Flight(validFlightNumber); // verify constructed object assertEquals(validFlightNumber, newFlight.number); assertEquals("", newFlight.airlineCode); assertNull(newFlight.airline); // set up mileage newFlight.setMileage(1122); // exercise mileage translator int actualKilometres = newFlight.getMileageAsKm(); // verify results int expectedKilometres = 1810; assertEquals( expectedKilometres, actualKilometres); // now try it with a canceled ļ¬‚ight newFlight.cancel(); try { newFlight.getMileageAsKm(); fail("Expected exception"); } catch (InvalidRequestException e) { assertEquals( "Cannot get cancelled ļ¬‚ight mileage", e.getMessage()); } } 25 Testing everything at a time Monday, 15 November 2010
  • 26. Testing everything at a time public void testFlightMileage_asKm2() throws Exception { // set up ļ¬xture // exercise constructor Flight newFlight = new Flight(validFlightNumber); // verify constructed object assertEquals(validFlightNumber, newFlight.number); assertEquals("", newFlight.airlineCode); assertNull(newFlight.airline); // set up mileage newFlight.setMileage(1122); // exercise mileage translator int actualKilometres = newFlight.getMileageAsKm(); // verify results int expectedKilometres = 1810; assertEquals( expectedKilometres, actualKilometres); // now try it with a canceled ļ¬‚ight newFlight.cancel(); try { newFlight.getMileageAsKm(); fail("Expected exception"); } catch (InvalidRequestException e) { assertEquals( "Cannot get cancelled ļ¬‚ight mileage", e.getMessage()); } } 26 Comments as deodorant Monday, 15 November 2010
  • 27. Testing everything at a time public void testFlightMileage_asKm2() throws Exception { // set up ļ¬xture // exercise constructor Flight newFlight = new Flight(validFlightNumber); // verify constructed object assertEquals(validFlightNumber, newFlight.number); assertEquals("", newFlight.airlineCode); assertNull(newFlight.airline); // set up mileage newFlight.setMileage(1122); // exercise mileage translator int actualKilometres = newFlight.getMileageAsKm(); // verify results int expectedKilometres = 1810; assertEquals( expectedKilometres, actualKilometres); // now try it with a canceled ļ¬‚ight newFlight.cancel(); try { newFlight.getMileageAsKm(); fail("Expected exception"); } catch (InvalidRequestException e) { assertEquals( "Cannot get cancelled ļ¬‚ight mileage", e.getMessage()); } } 27 Duplications with application logic? Monday, 15 November 2010
  • 28. Inappropriate dependencies ā€¢ Test setup depending on other tests ļ¬les ā€¢ A test ļ¬le depending on another test ļ¬le ā€¢ Stub functions depending on other tests extern int reg_ecx; // in the stub program int reg_exc; // in SUT 28 Monday, 15 November 2010
  • 29. What can we do? 29 Monday, 15 November 2010
  • 30. Try: one test group per ļ¬le But why canŹ¼t? is it because of... ? 30 Monday, 15 November 2010
  • 31. Test initialisation hard to read and shared among test groups in the same test ļ¬le ā€¢ Fixtures ā€¢ Test Data Builder ā€¢ Parameterised Creation ā€¢ make-it-easy 31 Monday, 15 November 2010
  • 32. Dont forget ļ¬xtures TEST_GROUP (TEST_thisObject) { void setup() { } void teardown() { } }; 32 Monday, 15 November 2010
  • 34. Parameterised Creation @Before public void setUp() throws Exception { alice = new Person(); alice.setId(1L); alice.setFirstname("Alice"); alice.setLastname("Adams"); alice.setSsn("111111"); billy = new Person(); billy.setId(2L); billy.setFirstname("Billy"); billy.setLastname("Burke"); billy.setSsn("222222"); clark = new Person(); clark.setId(3L); clark.setFirstname("Clark"); clark.setLastname("Cable"); clark.setSsn("333333"); alice.isInLoveWith(billy); } 34 Monday, 15 November 2010
  • 35. Parameterised Creation public class ParameterizedCreationMethodExample { private Person alice, billy, clark; @Before public void setUp() throws Exception { clark = createPerson("Clark", "Cable"); billy = createPerson("Billy", "Burke"); alice = createPerson("Alice", "Adams"); alice.isInLoveWith(billy); } private Person createPerson(String firstName, String lastName) { Person person = new Person(); person.setFirstname(firstName); person.setLastname(lastName); person.setId(UniqueNumber.next()); person.setSsn(String.valueOf(UniqueNumber.next())); return person; } @Test public void aliceShouldAcceptWhenProposedToByBilly() throws Exception { billy.proposeTo(alice); assertTrue(alice.isEngagedWith(billy)); } } 35 Monday, 15 November 2010
  • 36. make-it-easy 36 http://code.google.com/p/make-it-easy/ Maker<Apple> appleWith2Leaves = an(Apple, with(2, leaves)); Maker<Apple> ripeApple = appleWith2Leaves.but(with(ripeness, 0.9)); Maker<Apple> unripeApple = appleWith2Leaves.but(with(ripeness, 0.125)); Ā  Ā  Ā  Ā  Apple apple1 = make(ripeApple); Apple apple2 = make(unripeApple); Ā  Ā  Ā  Ā  Banana defaultBanana = make(a(Banana)); Banana straightBanana = make(a(Banana, with(curve, 0.0))); Banana squishyBanana = make(a(Banana, with(ripeness, 1.0))); Monday, 15 November 2010
  • 37. Try: One assertion per test 37 Monday, 15 November 2010
  • 38. Customised Assertions #define CHECK_OBJ(a,b) CHECK_OBJ(a,b, __FILE__,__FILE__) void CHECK_OBJ(struct* yourObj, struct* myObj, const char* file, int line) { if (structs are not equal) { SimpleString errorMessage = StringFromFormat( ā€œMy struct: %d, %p, %sā€, myObj->d, myObj->p, myObj->s); FAIL_LOCATION(errorMessage.asCharString(), file, line); } } 38 Monday, 15 November 2010
  • 39. At least: One concept per test 39 Monday, 15 November 2010
  • 40. Hamcrest ā€¢ Framework for writing declarative match criteria 40http://code.google.com/p/hamcrest/ String s = "yes we have no bananas today"; Matcher<String> containsBananas = new StringContains("bananas"); Matcher<String> containsMangoes = new StringContains("mangoes"); assertTrue(containsBananas.matches(s)); assertFalse(containsMangoes.matches(s)); assertThat(s, containsString("bananas")); assertThat(s, not(containsString("mangoes")); Or even better Monday, 15 November 2010
  • 41. Meaningful Assertion Messages 41 ā€¢ DonŹ¼t repeat what the built-in test framework outputs to the console (e.g. name of the test method) ā€¢ DonŹ¼t repeat what the test name explains ā€¢ If you donŹ¼t have anything good to say, you donŹ¼t have to say anything ā€¢ Write what should have happened, or what failed to happen, and possibly mention when it should have happened Monday, 15 November 2010
  • 43. Extra Constructor 43 public class LogFileMerge { private URL logFileA, logFileB; public LogFileMerge() { this(new URL("http://server1/system.log"), new URL("http://server2/system.log")); } LogFileMerge(URL a, URL b) { this.logFileA = a; this.logFileB = b; } } Monday, 15 November 2010
  • 44. Test-Speciļ¬c SubClass 44 public class CreditCardProcessing { public boolean isValid(String cardnumber) { return validationCodeMatches(cardnumber) && cardIsActive(cardnumber); } protected boolean validationCodeMatches(String cardnumber) { // validation logic omitted for brevity... } protected boolean cardIsActive(String cardnumber) { // access to merchant system's web service // omitted for brevity... } } Monday, 15 November 2010
  • 45. Still not testable? 45 ā€¢ Do you follow good design principles? Monday, 15 November 2010
  • 46. Thinking 46 Test code is not second class citizen Good design principles apply: ā€¢ Responsibility ā€¢ Dependency ā€¢ Low Coupling ā€¢ High Cohesion ā€¢ Indirection ā€¢ Protected Variations Watch out for organisational dysfunction! Monday, 15 November 2010
  • 47. References ā€¢ Practical TDD and ATDD for Java Developers - Lasse Koskela ā€¢ Growing OO Software, guided by tests - Steve Freeman ā€¢ xUnit Test Patterns - Gerard Meszaros 47 Steven Mak steven@odd-e.com www.odd-e.com twitter: stevenmak Monday, 15 November 2010