Turnleaf Design Ramblings of a junior developer

30Sep/090

A brief intro into unit testing with JUnit

Learning how to use the built-in IDE debuggers and write unit tests is as fundamental to being a developer as knowing how to write a for loop. These two tools will save you countless hours of frustration and help you write better code. Entire books are written on just these subjects, however today I will just give a simple tutorial on writing unit tests. In this example I will be testing a JavaBean that could be used in a simple inventory system. You can download the project here. If you need help setting up the project you can follow the instructions here.

package com.dining;

public class Item {
public String name;
public int id;

public Item(String name, String id) throws IllegalArgumentException{
if((name != null && !name.equalsIgnoreCase("")) && (id != null && !id.equalsIgnoreCase("") && id.matches("\\d*"))){
this.name = name;
this.id = Integer.parseInt(id);
} else {
throw new IllegalArgumentException("Invalid argument(s)");
}
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}
}

For my unit test I want to make sure my two argument constructor is working as expected. That is, it will require me to give a valid name, a String object with at least one character, and a valid id, a number. If either of these arguments are incorrect I will throw an IllegalArgumentException.

First we need to create a unit test class to run unit tests. To do this I will create a JUnit class, in Eclipse you can right click in your package explorer view and in the pop menu scroll down to the “JUnit” option, be sure to do this under the “com.unittest” package in the “test” folder. I will be using JUnit 3 for this example. The convention for naming for unit test classes is “Test” followed by the name of the class you will be testing, so in this case “TestItem.” The defaults should be fine so go ahead and click ok.

Each unit test case is its own method. Again the convention with unit tests is to start the name with “test” followed by the method under test. This is can be a looser practice as you might want to name the unit test based upon the type of test your are running. In this case I will name the unit test “testItemValidArguments” because I will be only passing valid arguments into the constructor. Inside the unit test you will make a call to the method you are testing and you will run an assertion to check to make sure the right value is being returned. There are numerous assertion types:

assetEquals(expected, actual) which compares what you are expecting to what is actually returned
assertTrue(condition) expects the passed condition to return true
assertFalse(condition) expects the passed condition to return false

There are a couple of other ways of running tests but these are the major ones. When these methods return an unexpected value; unequal values, false when true expected and vice versa, this causes the test to fail. If you are running your test in Eclipse the JUnit view will display red. Conversely if the test passes the JUnit view will display Green.

So lets write our first unit test:

public void testItemValidArguments() {
Item item = new Item("Wrench", "1");
assertEquals(2, item.getId());
}

No, I did not make a typo, go ahead and run the test an see what happens. Your test should fail (if it doesn't you have a problem). The JUnit view should look like this:

JUnit will let you know when you failed a test. In this case it's telling us that it was expecting “2” to be returned, but actually got “1.” Go ahead and change the expected value back to “1” and run the test again and it should pass. Ok so when we pass valid arguments the constructor works correctly. Now let's make sure the constructor lets us know when the arguments passed in are not valid. Let's write another units test:

public void testIteamInvalidArguments() {
Item item = new Item("Wrench", "A");
assertEquals(“A”, item.getId());
}

Try running the test. Your JUnit view should look like this:

Well good news bad news. The constructor validates the second field correctly, it is requiring a number, however we don't want our unit tests failing. All unit tests should “pass” when they run correctly so a change needs to be made. To cut to the chase this is one possible way of fixing the unit test:

public void testIteamInvalidArguments() {
try {
Item item = new Item("Wrench", "A");
fail("You should have thrown an exception!");
} catch (IllegalArgumentException e) {
//Do nothing
}
}

As long as a fail is not returned within a JUnit test case the test passes, so in the test case if the IllegalArgumentException is thrown then we won't do anything because we are expecting that, however if the exception is not thrown then we want the test to fail. So on the line below where I create an Item object I call fail() and pass in a message, so if the exception is not thrown the test will fail and I will know I have a problem (and a message will be displayed in the JUnit view).

I will end my tutorial here. This should be enough to get your feet wet in unit testing. There are several other tests that could be written, for example checking to make sure name validation works. I plan on covering this subject in more depth so check back later. This is my first real tutorial, so please let me know if I glossed over anything. If you have any other questions please let me know.

Bookmark and Share

Technorati Tags: , , ,

Related posts:

  1. Ramblings: Should unit tests talk to a data source?
  2. An Intro into Test Driven Development with JUnit4
  3. Mocking JDBC Connections with MockRunner
  4. 6 Steps for fixing any bug
  5. If, else and nothing else
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


No trackbacks yet.