There are many ways to write test cases. Overall, we can say a test case is a code fragment that programmatically checks that another code unit - a method - functions as expected. In order to make the testing process an efficient one, it is recommended to use a testing framework. 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.
Using a framework to develop your test cases has a number of advantages, most important being that others will be able to understand test cases and easily write new ones and that most development tools enable for automated and / or one click test case execution. Which of the frameworks you'll choose, that's a matter of personal preference. Both enable you to properly test your code, are equally well supported by Java development tools that matter and both are easy to use. In this article we'll address only JUnit test case development issues.
How to Write Test Cases with JUnit
If you're using a version earlier then JUnit 4, it is mandatory for your test case to inherit from the TestCase class, like in the following code example:
public class ExampleTestCase extends TestCase {
...
}
JUnit Coding Conventions
A JUnit test case can contain multiple tests. Each test is implemented by a method. The declaration of a test method must comply to a set of conventions in order to help JUnit and associated tools to automate the discovery and execution of tests. These conventions are:
the name of the method must begin with "test", like in "testCreateUser",
the return type of a test method must be null,
a test method must not throw any exception,
a test method must not have any parameter.
Suppose you need to test the following method: public User createUser(String userName, String password1, String password2) throws PasswordDeosntMatchException { ... }. A typical test case for this method could look like this:
public class CreateUserTestCase extends TestCase {
public void testCreateUser() {v
...
}
public void testCreateUserFailPasswordDoesntMatch() {
...
}
}
How to Write a Success Test With JUnit
Why write three tests for one single method, you may ask? Well, this will be better explained in the article that explains how to develop test cases. For now, let's just say that you must not only test that your method works as expected under normal conditions, but also that it fails as expected when current environment configuration requires it.
The first method will simply call the method then compare the returned object with the provided parameters if the user was properly created. To compare the result with reference values you should use the assert family of methods. Also, we must not forget to force the test to fail if the exception is thrown when it is not supposed to. Here is how you could implement "testCreateUser()":
public void testCreateUser() {
try {
User ret = instance.createUser("john", "pwd", "pwd");
// use assertEquals to compare the name
// of the returned User instance with the reference value
assertEquals(ret.getUserName(), "john");
// use assertEquals to compare the pasword
// of the returned User instance with the reference value
assertEquals(ret.getPassword(), "pwd");
} catch (PasswordDeosntMatchException e) {
// force the test to fail, because the exception was thrown
// and it shouldn't have
fail();
}
}
The assertEquals method will compare the two provided values and if they're not equal, it will generate an internal exception which will inform JUnit about the failure. Also, if PasswordDeosntMatchException is thrown - knowing that this should not happen with the set of parameters we have provided - the fail() method will have the same effect. In either case, JUnit will mark the test as failed and report it as such. You can pass a message to the assertEquals and fail methods. This message will be shown in the report when that particular assertion fails, helping developers to more easily identify errors. This feature can be particularly helpful if you maintain a large test base each with many assertion points.