Monday, May 11, 2009

Shopping Cart Web Application - Test cases - Part 3

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
  • Beginner


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!

18 comments:

Shumani said...
This comment has been removed by the author.
Shumani said...

This is really a good start...it is really working for me...thanks Ross u are a star...keep on doing the good job...im ur best fan

Unknown said...

This tutorial is one of the best i have ever read.when ever a read it i learn something i didn't know before i started on it.i believe that it will make me a good Java developer.its the best and it keeps me going.....thanks Ross you're a Star

Unknown said...

thanks I am glad you are finding it useful. If you have any questions just shout

Unknown said...

shopping-cart-core-test-cases-part3
package com.mydomain.shoppingcart.exception;
ShoppingException.java

i don't understand how this class interact with other classes.

Unknown said...

Yes good point. That class was added to cater for exception handling. As it so happens I never tied it to the application. I have updated all projects now so that it caters for this. This custom exception is only introduced in the hibernate tutorial.

Thanks for pointing this out.

Unknown said...

thanks Ross,it works now. i think you can go to Tiffany's for coffee because i wil be back soon with more problems

Unknown said...

LOL -- more problems or more questions? I hope more questions. A strong coffee sounds like a good idea :-)

Unknown said...

they just all seem to be problems;

right now i cant deploy my project,whenever i click add or remove projects i get the following error message; no projects can be added

secondly all my newly created web projects come without web content,what could b the cause of this, i manually created webcontent,WEB-inf, and web.xml
does that solve the problem

Unknown said...

If you downloaded the project and all the library dependencies and imported the project into your workspace you shouldn't have to modify or edit any of the files in the project. I can't see what your Tomcat installation looks like but can you run it without any projects deployed and does it run without errors?

Have you looked at the errors view or the problems view in Eclipse? Are there any messages / errors there? Does your project compile without errors or warnings?

In regards to your own projects you need to be able to create a web project in Eclipse in order to deploy it to Tomcat. What type of project do you create?

Unknown said...

morning Ross,

when i run my server it gives the following error

INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/lib/../lib/gcj-4.3-90:/usr/lib/xulrunner-addons:/usr/lib/jni

Unknown said...

That's just an INFO message not an error.

Unknown said...

ok thanks a lot Ross

Unknown said...

hi Ross

i am googling up examples on unit tests, and i keep coming up with test classes that are based on JUnit 3 ,where can i find the JUnit 4 tests ,and y r they so scarce

Unknown said...

I did a quick search in Google for JUnit4 and came back with a lot of results.

Have you been to JUnit's webpage? Visit their website documentation

Unknown said...

sure Ross i have been to that site and i really found it helpful

Karen said...

Hi Ross,
Am trying to learn up your tutorial.  Not sure if I'm using a newer version of Eclipse which is Indigo eclipse ..I just can't do the part about what you covered under JUNIT.  After created the import the project into Eclipse, I created a LIBS folder under the general project.  But, I can't find Java Build Path at all under properties....Please help. Thanks.

rmahony said...

Hi Karen, 

I use Indigo now as well. One day I need to update this tutorial as I do things a little differently now. In any case to find where to set your build in Indigo you can do this:1. right click on the shopping cart project. Should display a menu popup2. At the bottom of the menu there should be Properties. Click on this3. A window should popup and on the left hand side you should see Java Build Path