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
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
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
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
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
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
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