290 likes | 496 Views
Unit Testing with JUnit. CS 3331 Fall 2009 Kent Beck and Eric Gamma. Test Infected: Programmers Love Writing Tests, Java Report , 3(7):37-50, 1998. Available from: http://junit.sourceforge.net/doc/testinfected/testing.htm. Unit Testing. Introduction Conventional approach
E N D
Unit Testing with JUnit CS 3331 Fall 2009 Kent Beck and Eric Gamma. Test Infected: Programmers Love Writing Tests, Java Report, 3(7):37-50, 1998. Available from: http://junit.sourceforge.net/doc/testinfected/testing.htm
Unit Testing • Introduction • Conventional approach • Unit testing with JUnit • More on JUnit
Testing in General • Testing • A way of showing the correctness of software • Phases • Unit testing • To test each module (unit, or component) independently • Mostly done by developers of the modules • Integration and system testing • To test the system as a whole • Often done by separate testing or QA team • Acceptance testing • To validate system functions for (and by) customers or user
What Is Unit Testing? • Definition • Testing is the process of showing that a program works for certain inputs. • A unit is a module or a small set of modules. • In Java, a unit is a class or interface, or a set of them, e.g., • An interface and 3 classes that implement it, or • A public class along with its helper classes. • Unit testing is testing of a unit.
Question • Do you get more confidence by running more test data?
Why Unit Testing? • Code isn’t right if it’s not tested. • Practical • Most programmers rely on testing, e.g., Microsoft has 1 tester per developer. • You could get work as a tester. • Divide-and-conquer approach • Split system into units. • Debug unit individually. • Narrow down places where bugs can be. • Don’t want to chase down bugs in other units.
Why Unit Testing? (Cont.) • Support regression testing • So can make changes to lots of code and know if you broke something. • Can make big changes with confidence.
How to Do Unit Testing • Build systems in layers • Starts with classes that don’t depend on others. • Continue testing building on already tested classes. • Benefits • Avoid having to write (test) stubs. • When testing a module, ones it depends on are reliable.
Question • How does low coupling help testing? • How does high coupling hurt it?
Program to Test public final class IMath { /** * Returns an integer approximation to the square root of x. */ public static int isqrt(int x) { int guess = 1; while (guess * guess < x) { guess++; } return guess; } }
Conventional Testing /** A class to test the class IMath. */ public class IMathTestNoJUnit { /** Runs the tests. */ public static void main(String[] args) { printTestResult(0); printTestResult(1); printTestResult(2); printTestResult(3); printTestResult(4); printTestResult(7); printTestResult(9); printTestResult(100); } private static void printTestResult(int arg) { System.out.print(“isqrt(“ + arg + “) ==> “); System.out.println(IMath.isqrt(arg)); } }
Conventional Test Output Isqrt(0) ==> 1 Isqrt(1) ==> 1 Isqrt(2) ==> 2 Isqrt(3) ==> 2 Isqrt(4) ==> 2 Isqrt(7) ==> 3 Isqrt(9) ==> 3 Isqrt(100) ==> 10 • What does this say about the code? Is it right? • What’s the problem with this kind of test output?
Solution? • Automatic verification by testing program • Can write such a test program by yourself, or • Use a testing tool such as JUnit. • JUnit • A simple, flexible, easy-to-use, open-source, and practical unit testing framework for Java. • Can deal with a large and extensive set of test cases. • Refer to www.junit.org.
Testing with JUnit import junit.framework.*; /** A JUnit test class to test the class IMath. */ public class IMathTest extends TestCase { /** Tests isqrt. */ public void testIsqrt() { assertEquals(0, IMath.isqrt(0)); // line 23 assertEquals(1, IMath.isqrt(1)); assertEquals(1, IMath.isqrt(2)); assertEquals(1, IMath.isqrt(3)); assertEquals(2, IMath.isqrt(4)); assertEquals(2, IMath.isqrt(7)); assertEquals(3, IMath.isqrt(9)); assertEquals(10, IMath.isqrt(100)); }
Testing with JUnit (Cont.) /** Returns the test suite for this test class. */ public static Test suite() { return new TestSuite(IMathTest.class); } /** Run the tests. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); // junit.swingui.TestRunner.run(suite()); } }
Compilation and Output • $ javac IMath.java IMathTest.java • $ java IMathTest • .F • Time: 0.02 • There was 1 failure: • testIsqrt(IMathTest)junit.framework.AssertionFailedError: expected:<0> but was:<1> • at IMathTest.testIsqrt(IMathTest.java:23) • at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) • at sun.reflect.NativeMeth... • at sun.reflect.Delegating... • at IMathTest.main(IMathTest.java:17) • FAILURES!!! • Tests run: 1, Failures: 1, Errors: 0 • Question: Is this better? Why?
Exercise • Write a JUnit test class for testing public class ForYou { /** Return the minimum of x and y. */ public static int min(int x, int y) { ... } }
Exercise (Cont.) public class ForYou { /** Return the minimum of x and y. */ public static int min(int x, int y) { ... } } By filling in the following: import junit.framework.*; /** Test ForYou. */ public class ForYouTest extends TestCase { /** Test min. */ public void testMin() { } // the rest as before … }
Some Terminology • Definition • A test data (or case) for a method M is a pair of (o, args), where • o is not null and M can be sent to o, • args is a tuple of arguments that can be passed to M. • A test data, (o, args), for M succeeds iff o.M(args) behaves as expected. • A test data, (o, args), for M fails iff it does not behave as expected. • Question • Why should o not be null? • If M has a bug that is revealed by a test data, does that test data for M succeeds or fails?
Parts of Test Code • Definition • The test fixture is the set of variables used in testing. • The test driver is the class that runs the tests. • The test oracle for a test data is the code that decides success or failure for that test data. • Question • What in the code we saw so far was the test driver, and the oracle? • What difference is there between JUnit testing and non-JUnit testing in what we saw before?
Basic Usage of JUnit To test a type T: 1. Write a class like: import junit.framework.*; /** A JUnit test class for the class T. */ public class TTest extends TestCase { /** Runs the tests. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** Returns the test suite for this test class. */ public static Test suite() { return new TestSuite(TTest.class); } <test methods go here> }
Basic Usage of JUnit (Cont.) 2. Compile T.java and TTest.java $ javac T.java TTest.java 3. Run the JUnit graphical user interface on TTest $ java junit.swingui.TestRunner TTest or Run the text interface (good from makefiles) $ java TTest 4. Look at the failures and errors
Naming Convention • Test methods start with “test” e.g., testIsqrt, testMin • Test classes end with “Test” e.g., IMathTest, ForYouTest
Assertion Methods Method Description assertEquals(a,b) Test if a is equal to b assertFalse(a) Test if a is false assertNotSame(a, b) Test if a and b do not refer to the identical object assertNull(a) Test if a is null assertSame(a,b) Test if a and b refer to the identical object assertTrue(a) Test if a is true - Static methods defined in junit.framework.Assert - Variations taking string error messages
More on JUnit -- Test Fixture • Sharing test data among test methods public class TTest extends TestCase { // other methods here … protected void setUp() throws Exception { // initialize test fixture variables. } protected void tearDown() throws Exception { // uninitialize test fixture variables. } // test fixture variables, i.e., fields shared by several test methods. }
Example public class PointTest extends TestCase { private Point p; // test fixture variable protected void setUp() { // initializes text fixture variables p = new Point(10, 10); } protected void tearDown() { } // clean up text fixture variables public void testSetX() { // tests SetX p.setX(20); assertEquals(20, p.getX()); } public void testSetY() { // tests SetY p.setY(30); assertEquals(30, p.getY()); } // template and other test methods here… }
More on JUnit -- Test Suite • Definition • A test suite is a set of test methods and other test suites. • Test Suite • Organize tests into a larger test set. • Help with automation of testing.
Example public class AllTestSuite extends TestCase { /** Returns the test suite for this test class. */ public static Test suite() { TestSuite suite = new TestSuite() { public String toString() { return "Test suite for Project T"; } }; suite.addTestSuite(T1Test.class); suite.addTestSuite(T2Test.class); … suite.addTestSuite(TnTest.class); return suite; } // the rest of methods as before … }
More on JUnit? • Refer to www.junit.org • JUnit APIs available from the course Web page