This document summarizes the application of test-driven development (TDD) on the construction of the Web'n'walk-3 mobile internet portal for T-Mobile International. Key points:
1) TDD was introduced partway through the project to improve low test coverage. Developers were given freedom in TDD application but coverage became non-negotiable.
2) Common pitfalls saw developers disillusioned by perceived reduced efficiency or writing tests dogmatically without benefits. Most learned from mistakes with coaching.
3) Rigorous TDD led to more cohesive, testable code structures compared to initial fragmented implementations. Refactoring was guided by test failures.
4) While challenges existed,
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Â
Test Driven Development Andrew Rendell Valtech
1. Effective and Pragmatic Test Driven Development
Andrew Rendell
Valtech
andrew.rendell@valtech.co.uk
Abstract
Test Driven Development has long been a key tool required to run under significant load twenty four
in the agile toolbox. Often it is suggested that the hours a day, every day of the year.
technique has moved into the mainstream and that not Unlike previous incarnations of the mobile internet
applying a test first approach is exceptional. Recent portal at T-Mobile, the Webânâwalk-3 home page
coverage in the community has even started to could be personalized. Customers could add widgets
describe a post-TDD approach. Having worked with which displayed their favorite content. A variety of
TDD for the last five years with varying degrees of widgets providing everything from news to email
rigor and success I have observed that far from being clients existed.
ubiquitous, effective application of TDD is
From October 2007 the Webânâwalk-3 application
uncommon.
was live in a number of European countries.
This paper takes a pragmatic approach in
T-Mobile is very customer focused. As an
evaluating the implementation of, impediments
organization it prides itself on the stability and
against and measurable benefits of TDD on a large,
scalability of the systems providing customer services.
commercially successful, project. Analysis of this
This encourages its development organizations to be
experience will show how and why TDD is being used
conservative and employ very careful management of
incorrectly and how this situation can be corrected.
risk. At the same time the mobile telephony market is
The analysis will show how project delivery improved
one of the most competitive in the world of
when a more effective approach was applied.
telecommunications. This puts development groups
under pressure to respond quickly to stay on the
cutting edge.
1. Introduction These conflicting requirements of risk aversion
and rapid adaptability create an interesting software
This experience report details the application of development dynamic. Valtech believes that agile,
Test Driven Development on construction of the and in particular Test Driven Development can help
Webânâwalk-3 mobile internet portal at T-Mobile these companies deliver quickly and safely.
International in the UK.
In the summer of 2007 the marketing organization
T-Mobile International is of one of the largest within T-Mobile set their development teams a
mobile companies in the world, a major branch of challenge: To build a new mobile internet portal
Deutsche Telekom AG whose subsidiaries and which incorporated the latest Web2.0 experience
affiliated companies serve over 86 million mobile where possible but still delivered carrier grade quality.
customers worldwide. The marketing team set an exact date and time for
Webânâwalk-3 was the mobile internet portal for launch several months in the future. The timescales
T-Mobile customers. When a customer pressed the were much tighter than for previous projects and
internet button on their phone, the Webânâwalk-3 initially some doubted it was achievable. This
home page was to be displayed. This mandated that experience report details the small part that a fairly
the page be delivered as quickly as possible and the successful application of TDD helped in delivery of
application had to support a large number of that goal, on time.
concurrent requests. The Webânâwalk-3 portal was
2. 2. Introduction of TDD modules. This class implemented a number of methods.
Each method returned a model object in a state that
corresponded to a scenario in the use cases.
When a project is initiated how does it become
âtest drivenâ? In common with many other projects the For example, development of the email widget involved
Webânâwalk-3 application was not immediately the view and the server side developers sitting together and
identified as one that would be using TDD. At the creating a class with the following signature. This figure has
point TDD was first considered, the project had been been slightly revised for commercial and readability
running for several weeks and created a sizable body reasons.
of prototype code. There were some JUnit tests but
EmailWidgetModel XXXEmailContract
these lacked structure and there was no common +customerNotAuthenticatedWithPartner() : EmailWidgetModel
approach (or even clear intent) to achieve high +oneReadOneUnreadEmail() : EmailWidetModel
+noUnreadEmailFiveReadEmail() : EmailWidgetModel
coverage. As the project transitioned from elaboration +noEmail() : EmailWidgetModel
+manyEmails() : EmailWidgetModel
into a construction phase various new team members +errorGettingEmail() : EmailWidgetModel
were brought on board who identified that a TDD
approach should be employed. Immediately upon
XXXEmailAcceptanceTest
making this decision, the technical architect used the JUnit4 test
Cobertura code coverage tool to identify that test
coverage was very low and in several modules, non-
existent. XXXEmailWidgetService
2.1 Communicating the intent Figure 1: Contracts and Acceptance tests.
It was communicated to the developers that a test Part of the infrastructure developed by the team allowed
first approach was to be employed. As has been the the view developer to execute the methods in the contract
case on previous projects in my experience there was class. This injected the model object returned into the view
universal approval from the programmers for this under development. The view developer could then
decision. Programmers still consider TDD a cool progress with the complex task of building the UI for all the
technique and one worth adding to their repertoire. use case scenarios with no further dependency on the server
The team held a number of white board sessions side developer.
where the mechanics of TDD were discussed. The The server side developer then created one JUnit test for
technical architect felt that although several team every method in the contract class.
members were inexperienced in this area and would For example, the figure above details a contract class
make mistakes they did on the whole understand the with the method 'customerNotAuthenticatedWithPartner'.
objective of using TDD and the implementation The 'XXXEmailAcceptanceTest' class contains a test
details. 'testCustomerNotAuthenticatedWithPartner'. The xml
response from the email provider indicating non-
2.2 Enforce TDD through application authentication would be added to the behavior of a mock
structure HTTP client. All other configuration data, such as customer
database rows, would also be created.
The architecture of the Webânâwalk-3 application The system is then in a state where the model object
was essentially Model View Controller. The returned from a call to application should match the model
complexities of rendering the portal on mobile object returned by the above contract class method. The
browsers were encapsulated within the view. All other JUnit test executes this call and asserts that the resulting
functions such as customer identification, integration model objects are equal. At this point the acceptance test for
with downstream partners and enabling systems etc. this particular scenario has passed. These tests run against a
were encapsulated in a set of server side modules. The full application stack inside a Spring container. Only calls
interface between the views and the server side to external systems are stubbed.
modules were the model objects. The contract class above has become the test first
The realization of a widget presented to a definition of what is to be delivered. It is unambiguous and
customer included a set of views and a set of server easy to understand. The sprint backlog was prioritized so
side modules. The first activity in development of that that creation of this contract was the first activity addressed.
widget was the creation of a contract class intended to The last item on the backlog for the use case was the
capture the expected output of the server side successful execution of the entire acceptance test. This was
3. the measure by which the use case is deemed Often they made mistakes (see below) but then identified
âcompletedâ by the developer. and learned from those mistakes and went on to refine their
In summary, the use of TDD was encouraged by: technique. There were a limited number of developers who
did not respond positively to the experience. The sequence
⢠Making a clear statement that TDD was to be of events many developers experienced when adopting
used; TDD are listed here:
⢠Encouraging practical team discussions about
the benefits and implementation; 1. Start using TDD and writing tests at the same time
or before writing code.
⢠Using the Cobertura code coverage tool to
2. Possibly spend too long writing tests and get
regularly measure overall coverage and
consumed in applying the approach dogmatically.
identify âhot spotsâ of non-compliance;
3. Start to slip on the burndown and experience the
⢠Mandating a development approach which at
pressure of having a velocity markedly lower than
the very least guaranteed that development
that of their peers.
would always begin (and hopefully continue)
4. Find that refactoring work is taking longer than they
with a test;
expected because poor code structure has lead to a
large volume of fragile test code which also needs
2.3 Degree of freedom in application of the refactoring.
technique 5. Start to comment out tests or mark them with
@Ignore.
One of the most refreshing aspects of working in 6. Stop writing tests at all or vastly reduce the number
an agile team is the focus on practicality and of tests in place before code is checked in. Attempt
empowerment of the programmers. Whilst TDD had to write the tests last because the code can be
obvious benefits, the architect did not want to impose considered âcompleteâ in their SCRUM report
a regime that developers would either apply without the test (i.e. it can be used and nobody will
dogmatically or felt coerced into using at the expense immediately notice the poor coverage).
of their own creativity. Therefore TDD was the 7. Fail to catch up with retrofitting tests.
preferred development approach but it was not 8. End up with large areas of code without any testing
mandated. Developers were discouraged from writing which would take far too long to retrospectively
code before writing tests (other than the acceptance write tests for.
tests above), but it was not seen as a âseriousâ offence Most practitioners on our project made some or all of
not to do so. these mistakes. Even our best developers experienced
Empowering developers did occasionally result in events 1 through 4 in the first few iterations of
a reduction of quality (described in the next section). development. Efforts were made to identify developers who
Upon reflection, high test coverage, whether it was were falling into these traps as early as possible and provide
achieved through unit or integration tests, should have them with help. Often this was as simple as insisting that
been nonnegotiable. A developer could be brilliant they revisit their estimates for work.
enough that they produce low defect, well structured Developers who came away from the project with a
code without coding a test first. This does not help negative view of TDD were those who went through all the
subsequent, possibly less able, developers maintain above stages and still failed to correct their behavior.
that same code without the support of high test In many cases those developers had been seen as very
coverage. successful on other, non-TDD, projects. They had been held
in high regard by their peers and managers. Their
3. Pitfalls in implementing TDD perception was that they had a strong record of delivery
until they were forced to use TDD.
3.1 Disillusionment Burndown charts and the use of acceptance tests as the
definition of completeness gave a clear measure of progress
After initial enthusiasm, developers can come to on Webânâwalk-3. On the negative developer's previous
resent TDD as they perceive it as being a technique non-agile projects successful delivery may have been more
which reduces their efficiency. This is especially true subjective. These developers now perceived themselves to
when burndown charts and measurement of velocity be under far greater scrutiny through the burndown charts.
are introduced at the same time as TDD. They also noted that instead of just cutting code, as they
The majority of developers involved with the would have previously, they had to spend development time
Webânâwalk-3 project were new to TDD. Most started writing tests. Their (incorrect) conclusion was that it was
with enthusiasm and applied the approach with vigor. the application of TDD which was responsible for their lack
4. of success and acclaim on the new project. In my into a form for the Webânâwalk-3view. It was this area of
opinion, this was a major factor in those developers complexity that required particularly rigorous testing and is
disillusionment with TDD. the subject of this example.
As development progressed, requirements were refined
3.2 Dogmatic application and defects were reported. This led to a number of updates
to the code. As the class diagram (amended for commercial
Dogmatic application, especially common to new and readability reasons) shows, the structure of the module
practitioner, leads to increased costs without a degraded. The logic which implemented the transformation
corresponding return on investment. of data was implemented in three different locations. (This
During the initial development of Webânâwalk-3 should have been spotted by Greg no matter whether TDD
the Cobertura tool revealed an unexpectedly uneven was being used or not).
distribution of test coverage. Some modules had very Greg applied tests in a dogmatic fashion. It is likely that
high levels of coverage in domain objects and less in he did not always write the test first but built them to test
their services. Further investigation revealed that tests code he had just created. This meant he failed to recoup the
had been written with the sole purpose of increasing structural benefits to his code that might have applied. It is
code coverage without providing any additional value. worth noting that the code did have high test coverage,
The most obvious of these were tests on the gettters which was useful in later refactoring.
and setters of POJOs. Where tests would have been
most valuable, in the complex business logic of the HttpClient
Logic for implementation of transformation
services, there was less coverage. implemented piecemeal in several classes
Poor test coverage was more common in those
classes whose construction did not enable straight
forward test creation. More experienced developers AuctionWidgetModel WidgetService Worker XmlService
simply redesigned the code to make it more testable
when writing the test became onerous. In the majority
of cases this led to better code. Tests
Tests
AuctionWidgetModelTest WorkerTest
Occasionally this approach produced code that +testSelling() +testCombineWachingAndBuyingTotals()
Tests
was less elegant in some way that that of the
developerâs initial implementation. In some cases this Logic for testing data
inelegance took the form of slightly more lines of transformation implemented in XmlServiceTest
several different classes
code or possibly the removal of a novel new language +testWatchingData()
feature. Our general approach was that it was better to Figure 2: Low cohesion
have less elegant code if it could be tested with greater
ease and the purpose of those tests was more obvious. When other developers came to correct defects caused
by incorrect data transformation, they applied the TDD
4. Benefits approach. First they started with the data from the auction
site that reproduced the defect. Then they looked for the test
class in which to add the new test. It quickly became
4.1 Better cohesion
obvious there was an issue as there was no single place to
add the test. Instead two or sometimes three test classes had
As practitioners gain experience of TDD their
to be amended. This was an obvious âbad smellâ.
code quality increases. Classes become more cohesive
and less tightly coupled. In the next release a backlog item was executed which
called for the refactoring of this particular module. Using
The example below describes how one particular
the acceptance tests a second developer, Jo, started from the
module was initially implemented with a dogmatic
entry point to the system (the widget service in the above
and less effective approach to TDD. It was then
diagram) and worked down. Jo was very careful to ensure
refactored using a more refined approach which
that the tests classes were exercising a cohesive set of
resulted in a much better code structure.
functionality. Where a single test class performed very
Greg, a developer, was new to TDD. He was different types of test this was a cue for the class under test
tasked with the implementation of a module which to delegate functionality. This is classic O-O design which
would fetch customer account data from an auction could have been achieved using many other techniques but
site and deliver it to the Webânâwalk-3 view layer. TDD was found to be particularly methodical and rigorous.
The module had a particular area of complexity, the
transformation of the data from the auction site API
5. The construction of simple tests became a litmus would result in requests to different downstream systems.
for cohesive code. The end result was a much cleaner Those requests had to be executed in parallel. Failure to do
class structure where all the data transformations were so would have resulted in a page rendering time equal to the
in a single, simple class. The tests which defined how sum of all downstream request latencies. The aim was only
the propriety auction xml was interpreted were also to wait as long as the slowest request before completing a
encapsulated in a single class. page. A series of whiteboard sessions were held and a
The diagram below shows the revised class design by sketch was created. This parallelization
structure after refactoring. infrastructure was built at the same time as the classes that
would eventually use it. The final implementation of this
infrastructure component did achieve what it was intended,
All data transformation logic encapsulatred in
XmlAdatpor. All tests and test data in XmlAdatporTest.
but at a cost. It was difficult for client classes to use and
contained many features that seemed 'useful' to the
WidgetService Worker
HttpClient developer but were never used in anger. A later refactoring
exercise started development by building tests which were
driven by the client classes. The resulting solution was far
AuctionWidgetModel XmlAdaptor
smaller, simpler to use and had less defects. Partly this was
because the second time you do something you do it better.
A great part of it was due to focusing on the real use rather
than what was predicted.
XmlAdaptorTest
4.3 Virtuous circle of agility
Figure 3: High cohesion
Solutions architects and business stakeholders quickly
There were many other examples identified by the grasp that tests increase confidence of the functional
developers of the top down approach from the correctness of a given area. This makes them more
acceptance test leading to simpler classes with better confident in their support of other agile techniques such as
cohesion. refactoring. This introduces a virtuous circle where code
can be cut faster because developers know that they will be
4.2 TDD encourages YAGNI able to go back and optimize or add features later with
management approval. It also means that the code base
YouAintGoingToNeedIt as described in Ron stays dynamic and is less likely to be the subject of arbitrary
Jefferiesâ wiki posting with the same title [1] is a and all encompassing code freezes dictated by senior
powerful tool when building software. If there is no managers attempting to reduce risk of instability.
use for a particular feature, then it should not be built. The following is a powerful example of this virtuous
This appears so obvious that it hardly needs stating circle:
but far too often functionality is added speculatively,
A new requirement emerged from the marketing team in
especially when building infrastructure type libraries
the area of customer identification. Detailed analysis of the
for use by other parts of the system.
user population showed that a particular mobile handset
Driving development top down from the known to be in wide use but not thought to be popular for
acceptance tests encouraged developers to apply the mobile internet was actually responsible for a significant
YAGNI principle. They were naturally much less percentage of traffic on the network. The issue was that this
likely to build that extra piece of cool code which particular handset had some very specific requirements
turns out to be of limited benefit in meeting the user regarding the identification of the customer using it.
goal.
The code module responsible for identification was the
Infrastructure components that might be used by most complex of any in the system. It contained a myriad of
several different modules should be built in response business rules. It had dependencies on several downstream
to a requirement identified by writing a class which enabling platforms. Customer identification is very
requires that service. Building infrastructure important as it is obviously key to the operation of an
components before building any users of those application whose market differentiator was a personalized
components tends to lead to the YAGNI principle experience.
being violated.
Customer identification obviously has some critical
It was obvious from the early stages of the project security requirements, especially when presenting possibly
that some concurrency infrastructure was required. sensitive personal data such as emails. Protection of
Aggregation of content for a customerâs home page customersâ data is very important to T-Mobile. To mitigate
6. the risk of an error in this part of the system detailed lack the necessary experience which allows them to utilize
analysis had been performed by the development team it most effectively.
and solution architects. State machines had been When developers do gain the necessary experience in
formulated and captured in UML. These were then Test Driven Development and apply it pragmatically it does
used to construct a large suite of manual tests that enhance the structure of code.
were executed using a variety of handsets and radio
Test Driven Development was not responsible for the
networks by a very skilled tester.
success of Webânâwalk-3. It was however, one of many
Unfortunately at the point in the project where the important techniques applied by the team which allowed T-
new requirement was identified the human test Mobile to achieve a higher degree of adaptability than had
exercise had already been completed. A meeting was been exhibited by similar projects without sacrificing their
called and attended by representatives of testing, commitment to carrier grade quality.
solution architecture, program management and
development. The mood was somber. Given the teams
6. References
commitment to quality and the clientâs aversion to risk
in this area in particular it looked likely that
[1] Jeffries R. , Youâre NOT gonna need it!
incorporating the requirement would be impossible
http://www.xprogramming.com/Practices/PracNotNeed.html
without a slippage. This all changed when the solution
architect made the following, critical, statement:
âWe must not forget this is a very different system
to those we have gone live with in the past. We have
an extensive array of automated tests that the
developer built as part of the design and analysis of
the identification component. Peter [the human tester]
ran a very comprehensive test suite on this code and
proved it was correct. The bugs that Peter found were
fed back into Mattâs [the developer] JUnit tests. They
all pass now. We can make this new change with a
high degree of confidence that it wonât break the
existing functionality. We have not had a server side
system built like this in the past. It is a big step
forward. We can do this.â
The confidence that the TDD approach had given
the solution architect enabled him to make this
statement in an environment where carrier grade
quality is jealously guarded.
The change was made, the tests passed and this
part of the system went live and continues to operate
with a remarkable level of quality. The identification
component had seventeen discrete states in its state
machine. Its dependency graph included fourteen
different spring beans. During testing only five defects
were identified. After go live no defects were reported
in what is possibly the most complex single part of the
system. Four months after go live there was an update
in the enabling platforms which changed the way the
devices in question here were identified. This
introduced complex new states that were previously
un-testable outside of a mocked environment. No
defects were reported.
5. Conclusions
Test Driven Development appears to be a
technique that many developers are very aware of but