Introduction
Software testing is a very important aspect to any software development lifecycle. It provides stakeholders with information about the quality of the product that is being tested.
What you need before we get started
- You will need to install the Sun JDK on your local pc in order to compile the projects code. The version I used was JDK1.6.0_07. I recommend using this version or the latest in case you run into any problems with the different versions that are available.
- I use Eclipse as my IDE to develop in. You don’t need Eclipse if you are just going to read this tutorial but if you intend to test the application then I would recommend it.
- You can import the project I created for this tutorial into Eclipse and run the unit test case.
- You will need the following third party libraries in order to run the test:
What we will cover
- What is unit testing?
- Code generation
- Import generated source into Eclipse
- JUnit
- Create the unit test
- Annotations
- Running the test
Level
Testing
There are a number of different software testing methods, namely:
- Unit testing - tests the minimal software component, or module. Each unit (basic component) of the software is tested to verify that the detailed design for the unit has been correctly implemented.
- Integration testing - exposes defects in the interfaces and interaction between integrated components. Progressively larger groups of tested software components corresponding to elements of the architectural design are integrated and tested until the software works as a system.
- System testing - tests a completely integrated system to verify that it meets its requirements.
- System integration testing - verifies that a system is integrated to any external or third party systems defined in the system requirements.
This tutorial will only focus on unit testing. Unit testing is a software design and development method where the programmer verifies that individual units of source code are working properly. Unit testing is a simple and effective process that improves delivery, quality and flexibility of a project. Having unit tests makes it easier and safer to modify the code because the tests document and protect the intended behavior and will instantly catch any regressions. A unit is the smallest testable part of an application
The goal of unit testing is to isolate each part of the program and show that the individual parts are correct. A unit test provides a strict, written contract that the piece of code must satisfy. As a result, it affords several benefits. Unit tests find problems early in the development cycle.
The goal for this tutorial is to show you how to write a unit test for a particular class using a third party library called
JUnit.
Code Generation
I was able to take the class diagram we created in the
previous exercise and generate Java source from it using
ArgoUML. I used the generated source as my base project to work from and modified the code slightly. I also created a unit test class. Please download the file
ShoppingCartTestCasesPart3.zip that contains the shopping-cart-core-test-cases-part3 Eclipse project I created for this tutorial.
Import existing project into Eclipse
You can follow these steps to import the shopping-cart-core-test-cases-part3 project into Eclipse:
- Open Eclipse
- Select File from the top navigation menu
- Select Import
- Select Existing Projects into Workspace under the General folder
- Select the Select archive file radio button
- Browse to where you saved the ShoppingCartTestCasesPart3.zip file
- Make sure the shopping-cart-core-test-cases-part3 project is selected
- Click the Finish button
The shopping-cart-core-test-cases-part3 project should be imported into your Eclipse workspace. The project may not compile because it may require a library that isn't part of the project. The next section talks a little about configuring your project so that it is pointing to the required libraries.
JUnit
I have chosen to use
JUnit as a framework to build my tests. JUnit is a unit testing framework for the Java programming language. I added the JUnit library we are going to need for our test case to our project. How did I do this you ask? I chose to create a simple project called LIBS where I will store all my libraries inside. I copied the
JUnit library to the LIBS project. I than included the library in the projects classpath by right clicking on the project -> Properties -> Java Build Path -> Libraries -> Add JARs -> LIBS -> JUnit4.5.
Create the unit test
1. Create test source folder
I created a new source folder called test where all my test classes will go I also added it as a src folder by right clicking on the test folder -> Build Path -> Source -> Use as Source Folder.
2. Create test class
I created a package called com.mydomain.shoppingcart.service.test under the new test folder. And within this package I created the ShoppingServiceTest class.
ShoppingServiceTest.java
package com.mydomain.shoppingcart.service.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.mydomain.shoppingcart.bo.Basket;
import com.mydomain.shoppingcart.bo.Item;
import com.mydomain.shoppingcart.service.ShoppingService;
import com.mydomain.shoppingcart.service.impl.ShoppingManager;
/**
* @author Ross
*/
public class ShoppingServiceTest {
private Basket basket;
private ShoppingService shoppingManager;
private Item testItem;
private int itemsCount;
/**
* Tests adding an item to the basket.
*/
@Test
public void addItem() {
int itemCount = basket.getItemCount();
basket.addItem(testItem);
double expectedBalance = 0;
for (Item item : basket.getItems()) {
expectedBalance = expectedBalance + item.getPrice();
}
assertEquals(expectedBalance, basket.getBalance(), 0.0);
assertEquals(itemCount + 1, basket.getItemCount());
}
/**
* Tests emptying the basket.
*/
@Test
public void empty() {
basket.empty();
assertEquals(0, basket.getItemCount());
}
/**
* Tests finding items.
*/
@Test
public void findItems() {
try {
List<Item> allItems = new ArrayList<Item>(shoppingManager.findItems());
assertEquals(itemsCount, allItems.size());
} catch (Exception e) {
e.printStackTrace();
fail("Error in Shopping Manager");
}
}
/**
* Tests removing an item from the cart.
*/
@Test
public void removeItem() {
int itemCount = basket.getItemCount();
for (Item item : basket.getItems()) {
basket.removeItem(item);
break;
}
assertEquals(itemCount - 1, basket.getItemCount());
}
/**
* Sets up the test fixture.
*
* Called before every test case method.
*/
@Before
public void setUp() {
shoppingManager = new ShoppingManager();
itemsCount = shoppingManager.findItems().size();
testItem = new Item(1l, "Candy Cotton", "Candy coated milky tarts", 8.50d);
basket = new Basket();
basket.addItem(new Item(2l, "Jelly Beans", "Jelly icecream waffle cream", 18.99d));
basket.addItem(new Item(3l, "Jam Doughnut", "Strawberry jam and Christmas pudding", 23.00d));
}
}
Annotations
JUnit4 uses annotations to define which methods should be tested. The @Test line in the code is an example of an annotation. It is used to identify which methods should be treated as test methods. A test method will be executed when your JUnit tests are run.
Many APIs require a fair amount of boilerplate code (any code that is or can be reused in new contexts or applications without being changed much from the original). For example, in order to write a JAX-RPC web service, you must provide a paired interface and implementation. This boilerplate could be generated automatically by a tool if the program were “decorated” with annotations indicating which methods were remotely accessible.
Annotations are like meta-tags that you can add to your code and apply them to package declarations, type declarations, constructors, methods, fields, parameters, and variables. As a result, you will have helpful ways to indicate whether your methods are dependent on other methods, whether they are incomplete, whether your classes have references to other classes, and so on.
Annotation-based development relieves Java developers from the pain of cumbersome configuration. Annotation-based development lets us avoid writing boilerplate code under many circumstances by enabling tools to generate it from annotations in the source code. This leads to a declarative programming style where the programmer says what should be done and tools emit the code to do it.
Looking at our ShoppingServiceTest class we have a number of methods. The first is the setUp method. This method has a JUnit4 annotation defined above it called @Before. This method gets called before any test methods. It is used to initialize any global variables used within the test methods.
The following test methods are defined in our class:
- empty() - Empty a basket and check whether or not the basket has any items
- addItem() - Add an Item to the Basket then check whether or not the Item was added
- removeItem() - Remove an item from the basket then check whether or not the Item was removed
- findItems() - Lookup a list of all the items and compare the number of items retrieved with the actual number of items
Running the test
We will run our tests within Eclipse to do this right click on our test class ShoppingServiceTest.java -> Run as -> JUnit test.
JUnit should run and you should be able to see the results of your test in the JUnit View tab.
That is all on JUnit testing for now. I would strongly encourage you to write other tests and run them to really get comfortable with this framework. Until the next tutorial, happy testing!