|
Are
you ready to give Extreme Programming a try? In the second part
of his series, Pradyumn Sharma recommends you start with its approach
to testing
The XP’s approach to testing is an important
foundation which makes many of the other practices of XP easy to
implement. Even if you are not willing to go whole-hog with XP,
you will find that its approach to testing makes immense sense for
any software development project.
Conventional testing
Developers usually dislike testing. They know
that testing is important, but consider it to be an unavoidable
pain, something that takes away the time from their core activity—coding.
That is because they are not taught the right way of testing.
When a new software project begins, the developers
start pounding the keyboard to produce code. Typically, they write
a fairly long amount of code, before compiling it and seeing if
it works.
What kind of testing do they do at this stage?
Suppose it is a programme to take some inputs from a user, perform
some calculations, and display a result to the user. Nine times
out of ten the developers will feed in just one or two sets of simple
data, see that some output appears on the screen, and will conclude
that the job is completed. Time to move on to the next programming
task!
Real testing only begins when the delivery deadline
approaches. Suddenly, many bugs start surfacing. For each bug reported
the developers will say, “Oh I missed that one,” or
“I did not try this,” and start furiously hitting the
keyboard again to make some changes to their code.
They fix some bugs and new ones surface. They
fix the new ones and some more surface. By the time they think they
have fixed all the bugs, some of the older ones resurface. (And
many more are still lying undiscovered.)
As deadline pressure mounts, a lot of tinkering
here and there (to fix these nasty bugs that keep surfacing) leads
to a lot of chaos. Deadline comes and goes and the developers plead
for more time for testing.
Unit testing, the XP way
Now let us look at the XP approach to testing.
To take an example, suppose we have to write a function that has
to remove duplicate values from a sorted array.
The XP approach to writing this function and
testing it would be as follows. Identify some test cases first,
along with the expected results. Think of as many boundary conditions
as possible, and include test cases for them such as an array with
only one, two or three elements; an array with no duplicates; an
array with only one value repeating throughout; an array with a
solitary duplication at the beginning only; an array with a solitary
duplication at the end only; etc.
Next, write a unit testing programme that incorporates
all the test cases identified. The testing programme calls the duplicate-removal
function, once for each test case. It compares the results obtained
from the duplicate-removal function with the expected results that
you have earlier worked out. The testing programme finally prints
the outcome—whether all test cases passed, or any one or more
failed. If some test cases fail, the testing programme prints the
necessary information to identify them.
Only now you start writing the actual duplicate-removal
function. If the logic appears complex, initially you may only address
one, the simplest test case in your function. If you are comfortable
with the complexity of the logic, you may address more than one
test case (or all the test cases) in your first attempt itself.
Now run the testing programme. If any one or
more test cases fail, look at your code to see what needs to be
changed to make them pass. After you modify your code, re-run the
entire testing programme to test all the test cases all over again,
not just the ones that failed the last time.
As you modify your code and run the unit testing
programme, you may think of other conditions in which your duplicate-removal
function may not work properly. Include test cases for such conditions
in your testing programme.
Repeat this process till all the test cases pass.
No code is released (or integrated with the rest of the system)
until all the test cases pass. Even after all the unit tests pass,
you do not throw away your unit tests and the testing programme—you
retain them for future maintenance work.
Acceptance tests
The same approach is used not only for unit tests
(testing individual classes or programmes) but also for integrated
tests. Developers or customers (or both jointly) write the acceptance
tests for each use case of the system, and automate them in the
same way as individual unit tests are. A use case can be released
only if all the tests on that use case pass.
Testing during maintenance
After the code is released, if some bug is discovered
in future, you first include one or more test cases in your testing
programme to isolate that bug, and then modify your code to fix
it. After doing this you run, not just the newly added test case,
but all the earlier test cases once again. After all, you want to
have the confidence that the modifications made by you do not break
something else that was working correctly earlier.
Running all the test cases after every modification
is not a problem at all, as they are automated inside a testing
program. Rather it is fun as it lets you monitor the progress made
by you, and gives you greater confidence while making any further
modifications or improvements to the code.
Testing frameworks
You can further simplify the process of running
automated tests by using a testing framework such as JUnit. It is
an open source testing framework for Java programs, which allows
you to write, maintain and run your test cases. JUnit has been developed
by Kent Beck and Erich Gamma, and you can find it at www.junit.org.
Testing frameworks, based on the JUnit approach, are also available
for various other languages, such as C++ and Visual Basic.
Pradyumn Sharma is the CEO of Pragati Software.
He regularly conducts training programmes on Object-Oriented Analysis
and Design, Design Patterns, and Extreme Programming
|