Obviously you have to test your code to get it working in the first place
> You can do ad hoc testing (running whatever tests occur to you at the moment), or
> You can build a test suite (a thorough set of tests that can be run at any time)
Disadvantages of a test suite
> It’s a lot of extra programming
(This is true, but use of a good test framework can help quite a bit)
> You don’t have time to do all that extra work
(False—Experiments repeatedly show that test suites reduce debugging time more than the amount spent building the test suite)
Advantages of a test suite
> Reduces total number of bugs in delivered code
> Makes code much more maintainable and refactorable
(This is a huge win for programs that get actual use!)
In the Extreme Programming approach,
> Tests are written before the code itself
> If code has no automated test case, it is assumed not to work
> A test framework is used so that automated testing can be done after every small change to the code
(This may be as often as every 5 or 10 minutes)
> If a bug is found after development, a test is created to keep the bug from coming back
Consequences
> Fewer bugs
> More maintainable code
> Continuous integration—During development, the program always works—it may not do everything required, but what it does, it does right
There are two major java testing framework.
> JUnit is written by Eric Gamma of the GoF fame and Kent Beck. JUnit has long been un-unchallenged in the testing framework arena.
> TestNG, written by Cedric Beust is a newer framework, which uses innovative concepts, much of which have been picked up by JUnit in the 4.x versions.
JUnit
> JUnit is a framework for writing tests
> JUnit was written by Erich Gamma (of Design Patterns fame) and Kent Beck (creator of XP methodology)
> JUnit uses Java’s reflection capabilities (Java programs can examine their own code)
> JUnit helps the programmer:
# define and execute tests and test suites
# formalize requirements and clarify architecture
# write and debug code
# integrate code and always be ready to release a working version
> JUnit is not yet (as far as I know) included in Sun’s SDK, but an increasing number of IDEs include it
> BlueJ, JBuilder, and Eclipse now provide JUnit tools
> A test fixture sets up the data (both objects and primitives) that are needed to run tests
Example: If you are testing code that updates an employee record, you need an employee record to test it on
> A unit test is a test of a single class
> A test case tests the response of a single method to a particular set of inputs
> A test suite is a collection of test cases
> A test runner is software that runs tests and reports results
> An integration test is a test of how well classes work together
> JUnit provides some limited support for integration tests
How to write a JUnit test class
> A JUnit test class is a class you write that extends junit.framework.TestCase
# As usual, you can use the default constructor or write your own constructors
> Your test class will inherit the following methods:
# protected void setUp()
$ This a method that will be called before each of your test methods
$ Typically, you will override this method and use it to assign values to some instance variables you need in testing
# protected void tearDown()
$ This a method that will be called after each of your test methods
$ Typically you will just ignore this method, unless you need to close files
> You will also write any number of test methods, all of which have the form public void testSomething()
> Something is usually, but not necessarily, the name of the method you want to test.
How to write a JUnit test method
> Your test method should start with
public void testSomething(), where Something is any name you like (typically the name of the method you are testing)
> This is a normal Java method; you can put any Java in it that you like
> Your method will typically use one of the “assert methods”, such as assertEquals(expected_value, computed_value) or assertTrue(boolean_condition)
> You do not need to call these methods; as long as they are defined as above, they will be called automatically
> You do not need to do anything if the tests fail; the framework will take care of this for you
A simple example
> Suppose you have a class Arithmetic with methods int add(int x, int y) and boolean isPositive(int x)
public class ArithmeticTest extends junit.framework.TestCase {
public void testMultiply() {
assertEquals(4, Arithmetic.add(2, 2));
assertEquals(-15, Arithmetic.multiply(3, -5));
}
public void testIsPositive() {
assertTrue(Arithmetic.isPositive(5));
assertFalse(Arithmetic.isPositive(-5));
assertFalse(Arithmetic.isPositive(0));
}
}
BlueJ
> BlueJ provides support with commands such as Create Test Class and Create Test Method
> You can create objects on the test bench and move them to the fixture (and back again)
> BlueJ also has a “recording” mode where you create and manipulate objects, and BlueJ turns your actions into test code
> This is a first implementation and is still quite buggy
> It’s worth experimenting with, but you have to check the code produced to see if it makes sense
> BlueJ also makes it easy to run a single test, a suite of tests, or all tests
> BlueJ’s display of JUnit results is virtually identical to the way results are displayed by commercial IDEs, such as JBuilder
Test-Driven Development (TDD)
> It is difficult to add JUnit tests to an existing program
> The program probably wasn’t written with testing in mind
> It’s actually better to write the tests before writing the code you want to test
> This seems backward, but it really does work better:
> When tests are written first, you have a clearer idea what to do when you write the methods
> Because the tests are written first, the methods are necessarily written to be testable
> Writing tests first encourages you to write simpler, single-purpose methods
> Because the methods will be called from more than one environment (the “real” one, plus your test class), they tend to be more independent of the environment
Stubs
> In order to run our tests, the methods we are testing have to exist, but they don’t have to be right
> Instead of starting with “real” code, we start with stubs—minimal methods that always return the same values
> A stub that returns void can be written with an empty body
> A stub that returns a number can return 0 or -1, or whatever number makes least sense
> A stub that returns a boolean value should usually return false
> A stub that returns an object of any kind (including a String or an array) should return null
> When we run our test methods with these stubs, we want the test methods to fail—to report all kinds of errors
> This helps “test the tests”
