JUnit (at http://junit.org/) is a class library for writing unit tests for Java software.
Unit testing is normally practiced by developers, who write tests of individual program units to check them out before releasing them for inclusion in a larger project. It most naturally corresponds to the testing that students might do, since the focus is on testing the features or individual classes or modules. Other kinds of testing include integration testing, which usually focuses on testing interconnected collections of units to make sure they work together when they are integrated into a whole, functional testing, which usually focuses on ensuring an application meets its requirements, and acceptance testing, which is usually performed by a customer to assess whether a development organization has produced an acceptable (custom) product.
JUnit allows one to write software tests in the form of code, so the tests can be easily executed, and can be re-executed as often as you like with near-zero effort. Phrasing tests in the form of code is more useful than running tests by hand, since it makes the process of executing and managing tests very easy to include in automated build processes, and eliminates human error in conducting these actions.
Basic terms:
The Purpose of Testing: Running software tests can never prove that software is bug-free. The only thing you can determine conclusively through testing in general is when a test fails--then you can prove a bug exists. As a result, many people in the testing community say that the purpose of testing is to demonstrate bugs, so they can be fixed.
Unit tests: software tests of an individual software unit, such as an individual class.
Incremental testing: When a programmer writes individual tests side-by-side with the corresponding code, following the idea of writing a test for each small feature or behavior as that behavior is added to the class(es) being developed. Think "code a little, test a little".
Test-first coding: A variant of incremental testing where the programmer writes the test(s) for each little feature or behavior before writing the corresponding implementation. Normally, that means writing one or more tests that express what you intend to happen after you complete the next small increment of coding--these would naturally be test(s) that fail at first. But these tests express what you are trying to accomplish with your next incremental code addition, and then serve as a check of whether you achieved this goal once you have written the corresponding code. Think "test a little, code a little".
Test class: a
Java class that contains unit tests. For example, the
tests for a class Foo
might be written in a class
called FooTest
, which is a test class.
Test method: Within a test class, each separate "test" the author wishes to perform is phrased as a separate method within the test class. Each test method serves as a "check" for a particular desired feature or behavior.
Test fixture: A test class often sets up a fixed set of initial conditions that serves as the starting point for each test method in the test class. These initial conditions consist of one or more objects that have been configured in any desired state that the programmer thinks is best for running her tests. This initial arrangement of objects that serves as the initial conditions for each test method in a test class is called a test fixture.
Assertions: In order for a test to be effective, it must check something. That is, it most confirm that some desired effect has been achieved. Usually, that means a test will manipulate one or more objects, and then confirm that these objects ended up in the desired state. Each test method uses one or more assertions to express the expected outcome, and also to check that the expected outcome has been achieved.
Test Suite:
A test suite is a collection of tests. Despite the terminology
used in JUnit's documentation, most people think of individual
test methods as tests or test cases, and think
of one or more test classes as a test suite. So it makes
sense to talk about the "test suite for class Foo
"
(maybe just a single test class) as well as the "test suite for
Program Assignment 1" (maybe multiple test classes, covering all
of the classes that make up that assignment).
A Test Passes: If, when a test method is executed, all of its assertions pass, then the test also passes--meaning that all of the behavior checked by the test was achieved.
A Test Fails: If, when a test method is executed, one of its assertions fails, then the test also fails--meaning that at least some part of the behavior checked by the test was not achieved.
"If the bar is green, the code is clean!": Many IDEs summarize JUnit results graphically, using a progress bar that is green if all tests pass, and that turns red as soon as any test being executed fails. This has given rise to this XP phrase, which goes hand-in-hand with the XP idea that code is not added to a project until all tests pass--that is, until "the bar is green".
import the JUnit classes so you can use them in your code.
import junit.framework.TestCase; ...
your class should be named using the JUnit convention with the name of the class you are testing followed by the word Test.
If you class is named Student
, then your
test will be named StudentTest
import junit.framework.TestCase; public class StudentTest extends TestCase { // code goes here... }
test cases are defined using methods named testXXX()
typically your method will be named following the method you are
testing in your source code. The example to the right tests the
setName()
method, hence the name testSetName()
.
you have to test your assumptions/expectations of your code using
an assertXXX()
statement. These are defined in the
JUnit package.
ready to go! Run this code to see the results of testing the student class.
import junit.framework.TestCase; public class StudentTest extends TestCase { private Student aStudent; // fixture to be used for testing public void setUp() { aStudent = new Student("Joe", "888-2993"); } public void testSetName() { aStudent.setName("Manuel"); assertEquals(aStudent.getName(), "Manuel"); } }
import the JUnit classes so you can use them in your code.
import junit.framework.TestCase; public class StudentTest extends TestCase { // code goes here... }
fixtures are objects that are used in your test cases.
define your fixtures as private instance variables.
initialize your fixture in the setUp()
method
setUp()
is called before each call to each test case.
import junit.framework.TestCase; public class StudentTest extends TestCase { private Student aStudent; // fixture to be used for testing public void setUp() { aStudent = new Student("Joe", "888-2993"); // initialize it here } }
fixture objects created in setUp are new objects in each test case.
the two test cases on the right run succesfully
... public void testSetName() { assertEquals(aStudent.getName(), "Joe"); aStudent.setName("Manuel"); assertEquals(aStudent.getName(), "Manuel"); } public void testSomethingElse() { // aStudent .. is new here assertEquals(aStudent.getName(), "Joe"); assertEquals(aStudent.getID(), "888-2993"); } }
the LIFT library is included in the student.jar.
import student.*;
create your GUI test class as an extension of the GUITestCase class (part of student.jar)
import student.*; public class GUITest extends GUITestCase { // code goes here... }
in your setUp()
, create your GUI objects
and show them in the testing frame.
showInFrame()
is defined in the student.jar
import student.*; public class GUITest extends GUITestCase { private PushCounterPanel aPanel; // fixture to be used for testing public void setUp() { aPanel = new PushCounterPanel(); showInFrame(aPanel); // to test it... } }
in your test cases, find an object from your interface
using getComponent()
and the
component filters defined in LIFT.
interact with your interface by clicking or typing or using the mouse, under test control
then check that your application is in the correct state.
public void testPushCounterPanel() { // You can retrieve components by name JButton pushMe = getComponent(JButton.class, "button"); JLabel count = getComponent(JLabel.class, where.nameIs("count")); // Interact with your interface, click the button click(pushMe); click(pushMe); // Then, check the state of components assertEquals("Pushes: 2", count.getText()); }
JUnit.org has more information on how to use JUnit.
Documentation for the asserts in JUnit: http://www.junit.org/apidocs/org/junit/Assert.html
Testing GUI Programs is a Prezi presentation that gives a good introduction to LIFT and how it is used.
The LIFT website provides more details on LIFT, including links to two sigcse papers, downloads, examples, and discussion forums.