The document summarizes a presentation on test-driven development (TDD) given by Luca Milanesio. The presentation discusses some of the challenges and downsides of TDD that can occur, such as tests becoming more complex than the code itself, or code being warped to accommodate tests rather than clarity. It also discusses how to rebuild TDD practices to focus on writing accurate, readable tests of appropriate size and scope.
2. 2 .io
About me
• Luca Milanesio
Co-founder of GerritForge
• over 20 years of experience
in Agile Development
SCM and ALM worldwide
• Contributor to Jenkins
since 2007 (and previously Hudson)
• Git SCM mentor
for the Enterprise since 2009
• Contributor to Gerrit Code Review community since 2011
3. 3 .io
Agenda
Why?
TDD-induced damage
Evangelist vs. Professional
Reboot
Professional TDD
Learning to write
4. 4 .io
TDD is 20 years old
http://www.macqueen.us/smalltalkReport/ST/91_95/SMAL0402.PDF
5. 5 .io
TDD has been widely adopted
http://www.indeed.com/jobtrends?q=test+driven+development&relative=1
6. 6 .io
Hold on … what's that ?
http://www.indeed.com/jobtrends?q=test+driven+development&relative=1
7. 7 .io
… and that ?
http://martinfowler.com/articles/is-tdd-dead/
8. 8 .io
Test-induced design damage
By David Heinemeier Hansson on April 29, 2014
http://david.heinemeierhansson.com/2014/test-induced-design-damage.html
"Code that's hard to test in isolation is poorly designed", goes a common TDD maxim.
Isolation meaning free of dependent context and separated from collaborators, especially "slow" ones like database or file IO.
The prevalent definition of "unit" in unit testing (though not everyone agrees with this).
This is some times true. Some times finding it difficult to test points to a design smell. It may be tangled
responsibilities or whatever. But that's a far ways off from declaring that hard-to-unit-test code is always poorly designed, and
always in need of repair. That you cannot have well-designed code that is hard to unit test.
It's from this unfortunate maxim that much of the test-induced design
damage flows. Such damage is defined as changes to your code that either facilitates a) easier test-first, b) speedy
tests, or c) unit tests, but does so by harming the clarity of the code through — usually through needless
indirection and conceptual overhead. Code that is warped out of shape solely to
accommodate testing objectives.
9. 9 .io
TDD EXAMPLE DAMAGE
ON A
LARGE PROJECT
https://www.flickr.com/photos/martinluff/5475631631
10. 10 .io
Code metrics of one service
340 Java Classes
880 Tests
158 Mocks
99.5% Code Coverage
11. 11 .io
TDD seniority and practices
Devs with two digits' years' experience
TDD applied with discipline from start
Code constantly covered by tests
Build time: 2 minutes (~ 130 msec per test)
12. 12 .io
Test example
@Test
public void shouldGetNewDTOFromEntity() {
// Given
DTO expectedDTO = DTOFixture.getDefaultRewardWithOneVariant().build();
Reward entity = VariantRewardFixture.getDefaultRewardWithOneVariant().build();
// When
DTO variantDTO = entity.transformToDTO();
// Then
assertThat(variantDTO, is(not(nullValue())));
assertThat(variantDTO, is(reflectionEquals(expectedDTO)));
}
14. 14 .io
THAT'S GOOD TDD
OR NOT?
http://icongal.com/gallery/icon/17045/256/thumbs_up_thumbs_up_vote_like
15. 15 .io
Features velocity
For every new feature we did:
End-to-End user-journeys acceptance test
Service-to-Service integration test
Component-to-component integration tests
Unit tests (with mocks)
16. 16 .io
… and their planning meeting
[TechLead]"How many points for this story ?"
[Devs] "2 .. 5 .. 5 .. 5"
[TechLead]"5 ? C'mon … for that small change?"
[Devs] "Change is trivial, but it will take some time to
amend all the tests and getting a green build"
17. 17 .io
But with more quality?
At the beginning yes
Project grew, tests base grew as well
Breaking tests became the norm
Less frequent refactor, for not breaking tests
Tech debt increased over time
18. 18 .io
WHAT WENT WRONG?
https://www.flickr.com/photos/crystalflickr/145082274
19. 19 .io
I AM NOT
TDD EVANGELIST
Evangelists are "relaying information about a particular set of
beliefs with the intention of converting the recipient"
http://en.wikipedia.org/wiki/Technology_evangelist
http://school.point2educate.com/wp-content/uploads/2014/03/Book-Red.png
20. 20 .io
I AM
TDD PROFESSIONAL
Professionals are "members of the profession with the particular knowledge
and skills necessary to perform the role of that profession"
http://en.wikipedia.org/wiki/Professional
http://www.levantar.co.uk/images/images/Lean_Legal_Professional_Firms.jpg
22. 22 .io
Step 1 – TEST RED
Write the test, without any code written yet
RED: test fails
(compilation errors are considered failures as well)
23. 23 .io
Step 2 – TEST GREEN
Make test work as quickly as possible
GREEN: test passes
(code satisfies the test assertions)
24. 24 .io
Step 3 – CODE REFACTOR
Keep the test code unchanged
Rework the implementation to make it
clean, DRY, flexible
GREEN: new code passes the test
(reworked code behaves exactly as before)
25. 25 .io
TEST
IS THE HEAD OF ALL
TDD CYCLE
http://www.improveit.mx/Imagenes/tdd_esquema_en.jpg
26. 26 .io
TDD
ASSUMES THAT
TEST IS CORRECT
http://www.wisteriaformations.co.uk/articles/wp-content/uploads/2011/09/Company-Formation-15.jpg
27. 27 .io
BUT WHAT IF
TEST
IS NOT 100%
CORRECT?
http://blogs.warwick.ac.uk/images/fsavva/2012/04/16/question-mark-man.jpg?maxWidth=500
29. 29 .io
Step 1 – TEST RED-ish
Write the [incorrect] test, no code exists yet
RED: fails, but maybe the test is wrong?
(nothing works, who can tell what is really wrong?)
30. 30 .io
Step 2 – TEST GREEN-ish
Make test work as quickly as possible
GREEN: [incorrect] test passes
(is code correct or wrong? nobody really knows)
31. 31 .io
Step 3 – CODE REFACTOR-ish
Keep the test code unchanged
Rework the implementation to make it
clean, DRY, flexible
GREEN: reworked code passes the tests
(was the code correct before?
Is the code still correct after?)
32. 32 .io
?
What is TESTING?
How to TEST the length of a table?
Use your foot Or a RULER?
33. 33 .io
How can I test the TEST?
How do you test a ruler?
?
Your thumb? Or a digital caliper?
34. 34 .io
And how can I test the test of a TEST?
How do you test a digital caliper?
YOU DON'T
[One meter is express in terms of speed of light]
35. 35 .io
Test and accuracy
TEST has to be
MORE ACCURATE
than CODE
36. 36 .io
Test and confidence
TEST cannot be tested
but we have
CONFIDENCE to be
VALID
K =
299,792,458 m / s
38. 38 .io
Be more accurate than this code ?
@RequestMapping(value = "/edit", method = RequestMethod.POST)
public ModelAndView update(@RequestParam String resourceId,
@ModelAttribute(PARTNER) UserPayload partner,
BindingResult result, SessionStatus status) {
boolean isTokenExists = partner.getTokensDefined();
if (partner.getUserSupplyTypesCodes() == null) partner.setUserSupplyTypesCodes(new HashSet<String>());
if (isTokenExists) partner.getUserSupplyTypesCodes().add("Identity");
UserRole partnerRole = currencyManager.getUserRoles(partner.getCode());
if (partnerRole.isIssuingUser()) partner.getUserSupplyTypesCodes().add("Issuance");
if (partnerRole.isLiabilityUser()) partner.getUserSupplyTypesCodes().add("Liability");
try {
partnerService.updateUser(partner, URI.create(resourceId));
status.setComplete();
return new ModelAndView("redirect:/partners");
} catch (ValidationErrorsException e) {
SpringErrorBindingHelper.populateErrors(result, e.getViolations(ViolationSeverity.ERROR));
ModelAndView mav = new ModelAndView("administration/partners/edit");
partnerRole = currencyManager.getUserRoles(partner.getCode());
mav.addObject(PARTNER_ROLE, partnerRole);
mav.addObject(RESOURCE_ID, resourceId);
populateReferenceData(mav);
return mav;
}
}
39. 39 .io
And this test?
"Sending two JSON records to the messages REST API" should {
"returns HTTP Status 200 and store two records to the messages repository" in {
// Given
val jsonRows = Json.parse(
"""[
|{ "id": "1234567890", "form": "SA300", "dispatchOn": "2013-11-22", "detailsId": "W0123456781234569"},
|{ "id": "1234567891", "form": "SA316A", "dispatchOn": "2013-11-23", "detailsId": "C0123456781234568"}
|]""".stripMargin)
// When
verifyStatusCode(doPut(resource(s"/messages"), jsonRows), 200)
// Then
val messages = await(messageRepository.findAll)
messages should have size 2
exactly(1, messages) should have (
'recipient("1234567890"),
'body("SA300", DetailsId("W0123456781234569")),
'dispatchOn(new LocalDate(2013, 11, 22))
)
exactly(1, messages) should have (
'recipient("1234567891"),
'body("SA316A", DetailsId("C0123456781234568")),
'validFrom(new LocalDate(2013, 11, 23))
)
}
}
40. 40 .io
Compared to this code ?
def putMessages = Action.async(action.parser) {
implicit request =>
withJsonBody[List[PrintSuppressionNotification]] {
messages =>
if (messages == null || messages.isEmpty)
throw new BadRequestException("No messages supplied")
if (messages.size > maxMessages)
throw new RequestEntityTooLargeException(
s"${messages.size} items submitted, max $maxMessages allowed")
val results = mongo.insertAllUnique(messages.map(_.toMongo))
Future.sequence(results).map(_ => Results.Ok)
}
}
41. 41 .io
Other projects' testimonials
"Today however, my team told me the tests are more complex
than the actual code. (This team is not the original team that wrote the code and unit tests. Therefore
some unit tests take them by surprise. This current team is more senior and disciplined.) In my opinion,
now that’s waste..."
Richard Jacobs at Sogeti (Sogeti Nederland B.V.)
http://www.rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf
42. 42 .io
Accurate = Small
More code
=
more mistakes
Ideal size of a test? ~ 3 lines
Assumption, Action, Assertion
"Less is more"
[Ludwig Mies van der Rohe]
43. 43 .io
Accurate = Readable
We can trust what we understand
Make your test easy to read
Anyone would understand and validate it
44. 44 .io
Accurate = Explicit and repeatable
What You See is What Test Does
Again and again the same
No side-effects
No hidden logic in helper
No loops
No random values
45. 45 .io
Accurate = Traceable to a requirement
When test fails,
what stops working?
Use business domain names
use business stories names
for objects, actions and results
46. 46 .io
Accurate = Correct when fails
If I comment out a line of code,
does the test FAIL for the CORRECT reason?
Does the test returns an error (exception)
instead of a failure?
50. 50 .io
Are you telling me I should have less tests ?
Q [John Nolan]:
"The thing I've found about TDD is that its takes time to get
your tests set up and being naturally lazy I always want to write as little code as possible. The first thing I
seem do is test my constructor has set all the properties but is this overkill?
My question is to what level of granularity do you write you unit tests at?
..and is there a case of testing too much?"
A [Kent Beck]:
"I get paid for code that works, not for tests, so my philosophy is to test as
little as possible to reach a given level of confidence"
http://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/153565#153565
52. 52 .io
Experience over Rules
Writing CODE is MORE
than applying RULES
Reading CODE is MORE
than reading BOOKS
Common sense, Trial and Error
53. 53 .io
The Sense of Time
Test too complex to write ?
Kill the test (if the code is clean)
Test takes too long to understand?
Kill the test (if the code is readable)
Time (with TDD) < Time (without TDD)
or you are doing something wrong!
54. 54 .io
Cost / value trade-off
Writing tests costs money
Test marginal value > Test cost?
Is this code critical? Can it possibly fail?
Am I double-testing something covered?
Cost (with TDD) < Cost (without TDD)
or you are doing something wrong!
55. 55 .io
How big is my code-base with TDD?
How many test / code lines I am writing?
Confidence on uncovered code?
Size (Test) < Size (Code)
Do not test code that cannot break
Test / code ratio
56. 56 .io
Test Focus
Tests express WHAT to achieve
from user's perspective
Test WHAT can be measured
What can I measure on this?
public interface UserRepository {
void addUser(String username,
String first, String last);
}
57. 57 .io
Code confidence
Code (not Test)
tells HOW system works
Code (with Test)
gives confidence of correctness
We are confident on what is
clear + readable + repeatable
58. 58 .io
Writing code - Martin Fowler
"Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.”
[Martin Fowler - 1999 - Refactoring: Improving the Design of Existing Code]
59. 59 .io
Best writers in history – Ernest Hemingway
"In 1954, when Hemingway was awarded the Nobel Prize for
Literature, it was for his mastery of the art of narrative […] He
avoided complicated syntax. About 70 percent of the sentences are
simple sentences—a childlike syntax without subordination."
http://en.wikipedia.org/wiki/Ernest_Hemingway
60. 60 .io
Reading = learning to Write
Code Review
Read A LOT of code
Read good code, read bad code
Comment, exchange ideas
Challenge solutions
https://www.flickr.com/photos/jdn/4817970175
61. 61 .io
Write, experiment, throw waste
Write code, ask for feedback
Read your own code …
after days, weeks, months
Measure progress
Throw waste
Keep test and code clean, ALWAYS
62. 62 .io
Professional TDD Summary
1. TDD practices are not enough
2. Experience over Rules
3. Trade-off test time/cost and code benefit
4. Tests is WHAT to achieve
5. Code is confidence on DESIGN
6. Read code to become a better writer
7. Plan to throw test waste away
64. 64 .io
TDD resources for reading and learning
Is TDD dead hangouts series
http://martinfowler.com/articles/is-tdd-dead/
Unit-testing and waste management
http://www.rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf
Mockist vs. non-mockist TDD
http://martinfowler.com/articles/mocksArentStubs.html
65. 65 .io
Code-review resources
Guido Van Rossum about Code Review @Google
http://www.youtube.com/watch?v=CKjRt48rZGk
Code Review @SAP
http://www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/CodeReview.pptx
V. Subramaniam – About Code Review and Quality
http://www.agiledeveloper.com/presentations/caring_about_code_quality.pdf
66. Replay these slides: http://slideshare.net/lucamilanesio
Try Gerrit on-line: http://gerrithub.io/login
Learn Gerrit: http://gerrithub.io/book
Follow my Blog: http://gitenterprise.me
Learn more about code review
20% OFF Book discount for
33 Degree.org User Conference
Book CODE: dg7jnZ
eBook CODE: Wi86Zh