ObjectOriented Software Engineering An Agile Unified Methodology by
Object-Oriented Software Engineering: An Agile Unified Methodology by David Kung Chapter 20: Software Testing - Using JUnit, and Cobertura Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
What is JUnit? • • JUnit is an open source Java unit testing framework. JUnit features include: – – • Assertions for testing expected results Test fixtures for sharing common test data Test suites for easily organizing and running tests Graphical and textual test runners JUnit was originally written by Erich Gamma and Kent Beck. 20 -2 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
JUnit Design Goals and Assumptions • If a program feature does not have an automated test, then it will not work. • The assumption is much safer than accepting a programmer's claim that the feature work and work forever. • Requires little learning by using familiar tools. • The goal is to make tests easier to write. • It supports regression testing. • It supports test reuse. 20 -3 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Conventional Approach and JUnit • Developers' test cases appear in different forms: – print statements – debugger expressions – test scripts • JUnit implements test cases as objects using the command pattern – to provide a uniform treatment of test cases – to encapsulate test requests as an object 20 -4 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Creating Test Cases in JUnit • Three simple steps: 1. create a subclass of Test. Case. 2. write test cases as public void test<Test. Case. Name>() {. . . } methods 3. write a public static Test suite() method that adds the test cases to the test suite. • Compile the subclass and the component under test and run it in a Test Runner. 20 -5 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Creating Test Cases in JUnit public class Simple. Test extends Test. Case { public void test. Max() { int x=Math. max(5, 10); assert. True(x>=5 && x>=10); } public void test. Divide. By. Zero() {int zero= 0; int result= 8/zero; } public static Test suite() { return new Test. Suite (Simple. Test. class); } } 20 -6 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
How to Compile Command line: javac –classpath junit. jar; <yourclasspath> -d <destination directory> <your source files> Today, JUnit is integrated into most of the IDEs. Follow the instruction given by the IDE to compile and run JUnit tests. 20 -7 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Running JUnit Tests java -cp junit. jar; <your_classpath> junit. awtui. Test. Runner 20 -8 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Enter the fully qualified Test. Case class name and click Run 20 -9 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
119 tests run successfully. 20 -10 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
JUnit Swing User Interface java -cp junit. jar; <your_classpath> junit. swingui. Test. Runner 20 -11 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
JUnit Swing User Interface Swing interface allows you to browse the directory. 20 -12 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
JUnit Text User Interface java -cp junit. jar; . junit. textui. Test. Runner junit. samples. All. Tests 20 -13 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Usefulness of Text UI? • You can redirect test output to a text file, and process the file to process the test output. • This is done by calling the static System. set. Out(Print. Stream out) method: try { Print. Stream ps=new Print. Stream ( new File. Output. Stream(“output-file. txt")); System. set. Out(ps); // invoke JUnit Text UI Runner here ps. flush(); ps. close(); } catch (IOException e) { e. print. Stack. Trace(); } // process output-file. txt here. 20 -14 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Error and Failure • Failures are anticipated failed conditions. • The tester tests for failure using the assertion methods: public void test. Add() { double result= 2+3; assert. True(result == 6); } • Errors are unanticipated failed conditions that cause runtime exceptions: public void test. Divide. By. Zero() {int zero= 0; int result= 8/zero; } 20 -15 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Error and Failure 20 -16 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
The Manual and Automatic Ways public class Simple. Test extends Test. Case { public void test. Divide. By. Zero() {int zero= 0; int result= 8/zero; } public static Test suite() { Test. Suite suite= new Test. Suite(); suite. add. Test(new Simple. Test ("test. Divide. By. Zero") { protected void run. Test() { test. Divide. By. Zero(); } }); return suite; } } public class Simple. Test extends Test. Case { public void test. Divide. By. Zero() { int zero= 0; int result= 8/zero; } public void test. Add() { double result= 2+3; assert. True(result == 6); } public static Test suite() { return new Test. Suite (Simple. Test. class); } } 20 -17 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Using Test Fixture A test fixture is an object used by one or more test cases. public class Vector. Test extends Test. Case { protected Vector f. Empty, f. Full; // fixtures protected void set. Up() { // setup the fixtures f. Empty= new Vector(); f. Full. add. Element(new Integer(1)); f. Full. add. Element(new Integer(2)); f. Full. add. Element(new Integer(3)); } } Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved. 20 -18
Using Test Fixture public void test. Capacity() { int size= f. Full. size(); for (int i= 0; i < 100; i++) f. Full. add. Element(new Integer(i)); assert. True(f. Full. size() == 100+size); } public void test. Contains() { assert. True(f. Full. contains(new Integer(1))); assert. True(!f. Empty. contains(new Integer(1))); } 20 -19 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Testing a Vending Machine 20 -20 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
The Coin. Box Code package coinbox; import java. io. *; public class Coin. Box { private int cur. Amt, total; public int get. Cur. Amt () { return cur. Amt; } public void insert. Coin (int amt) throws Invalid. Coin. Exception { if (amt!=5&&amt!=10&&amt!=25) { throw new Invalid. Coin. Exception(); } this. cur. Amt += amt; System. out. println ("Current Amount is "+cur. Amt); } Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved. 20 -21
public int get. Total () { return total; } public void make. Change (int price ) throws Invalid. Price. Exception { if (price<=0) { throw new Invalid. Price. Exception(); } release(cur. Amt-price); cur. Amt = 0; total += price; } private void release (int amt) { System. out. println ("Release "+amt); } public void return. Coin () { release (cur. Amt); cur. Amt=0; } } 20 -22 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Testing the Coin. Box import junit. framework. *; public class Coin. Box. Test extends Test. Case { private Coin. Box coin. Box; public Coin. Box. Test(String test. Case. Name) { super(test. Case. Name); } public void set. Up() {coin. Box=new Coin. Box(); } public void test. Total() throws Invalid. Coin. Exception {for(int i=1; i<=10; i++) coin. Box. insert. Coin(10); int total=coin. Box. get. Total(); assert. True("Total="+total+" Expected=100", total==100); } } 20 -23 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Coin. Box test. Total Failed 20 -24 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Coin. Box test. Cur. Amt() public void test. Cur. Amt() throws Invalid. Coin. Exception, Invalid. Price. Exception { for(int i=1; i<=10; i++) coin. Box. insert. Coin(10); int cur. Amt=coin. Box. get. Cur. Amt(); assert. True("cur. Amt="+cur. Amt+ "Expected=100", cur. Amt==100); } 20 -25 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
20 -26 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Class Exercise • Assume an integer stack has been implemented with the following methods: boolean empty () boolean full() int pop() void push(int x) • Write code to test the stack using boundary value analysis testing technique. Assume the stack can store 5 integers. Name the test case class Stack. Test. 20 -27 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Lab Exercise • Download JUnit http: //prdownloads. sourceforge. net/junit 3. 8. 1. zi p? download • Unzip to a clean directory. The installation is done. • Implement the integer stack. • Complete the implementation of the Stack. Test class. • Compile Stack and Stack. Test classes. • Run the test cases in Test. Runner. 20 -28 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Running JUnit in Net. Beans 1. Click Run->Set Project Configuration -> Customize. . . 2. In the Project Properties dialog that is displayed, click Run in the Categories list. 3. In the Main Class text field, fill in the test runner you want to use, e. g. , “junit. swingui. Test. Runner. ” 4. In the Arguments text field, enter the fully qualified Test. Case subclass name, e. g. , “test. example. Purge. Test. ” 5. Click OK. 20 -29 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
JCoverage, Cobertura, and Emma • Both are latest Java coverage tools. Cobertura is built on top of JCoverage. • JCoverage is a Net. Beans plugin. • It is easy to run these tools in Net. Beans. Use of Cobertura is recommended. • They support branch coverage and line coverage. • Emma is another coverage tool. But Emma may not provide branch coverage. 20 -30 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Running a Plugin in Net. Beans Step 1. Installation. Select Tools->Plugins, check the Code Coverage Plugin" check-box in the list of available plugins, click Install and follow the instructions. Step 2. Activation. Right click the project name in Projects view and select Coverage->Activate Coverage Collection. The tool is activated for the project. Step 3. Execution. Do as “Run JUnit in Net. Beans. ” Step 4. Viewing result. Right click on the project name and choose Coverage->Show Project Coverage Statistics. To see which lines of a class are exercised and which are not, double click the class name in Project view (green lines are covered completely, yellow lines are covered partially, and the rest are not covered). 20 -31 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Setting Up Cobertura in Net. Beans 1. Copy the build. xml and build. properties files in the cobertura-1. 9. 3examplesbasic directory to your Net. Beans project directory. 2. Rename the copies as cobertura-build. xml and cobertura-build. properties, respectively. 3. In the cobertura-build. properties file, change the line “cobertura. dir=. . /. . ” to refer to the path that contains the cobertura. jar file. It should be the path to the cobertura 1. 9. 3 directory. 4. Save the updated file. (to be continued) 20 -32 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Setting Up Cobertura in Net. Beans 5. (Optional. ) Move your test case Java source files from the project test directory to the project src directory. You may need to do this if your version of Cobertura only checks the src directory for the test case source files. You may change the cobertura-build. xml file to avoid moving the test files. 20 -33 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Running Cobertura in Net. Beans 1. Expand the cobertura-build. xml file in the Files view, rightclick the main task and choose Run Target. You should see the compile, instrument, run tests, and collect coverage information tasks being executed. 2. If all tasks run successfully, you should see the coverage information in the reports directory under the project directory. 3. Expand the cobertura-html directory to see a listing of html files. 4. Right-click the index. html file and select View from the popup menu to view the Coverage Report. 5. Right-click the index. html file under the junit-html directory and select View to see the unit test results. 20 -34 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Cobertura Coverage Report 20 -35 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Cobertura Unit Test Report 20 -36 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
More About JUnit • The following slides provide more about the design of the JUnit test tool. • These slides may be skipped. 20 -37 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
JUnit Framework Classes 20 -38 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
The Test Interface and Assert Class // more 20 -39 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
The Assert Class • The Assert class has the following types of methods: – methods for asserting • that two variables (including objects) are equal • that two object references refer to the same object • that two object references not refer to the same object • that an object reference is null or not null these methods may or may not have a informative message – methods for throwing an assertion. Failed. Error exception which may or may not include a message Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved. 20 -40
Methods that Throw Exceptions • static public void fail(String message) { throw new Assertion. Failed. Error(message); } • following methods use above method – fail( ): void gives no message – fail. Same(msg: String): void msg+" expect the same" – fail. Not. Same( msg: String, expected: Object, actual: Object ): void expect not the same objects – fail. Not. Equals( msg: String, expected: Object, actual: Object ): void expect not equal objects 20 -41 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
The Assertion Methods • The simplest one is protected void assert(boolean condition) { if (!condition) throw new Assertion. Failed. Error(); } 20 -42 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Methods to Assert Equals • Syntax: – assert. Equals([String message, ] type expected, type actual) • Semantics: – if (! expected. equals(actual)) throws assert. Failed. Error(message+" was expected to be equal. ") • type can be object or primitive types 20 -43 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
List of assert. Equals Methods assert. Equals( expected: double, actual: double, delta: double ): void assert. Equals( message: String, expected: float, actual: float, delta: float ): void assert. Equals( message: String, expected: long, actual: long ): void assert. Equals( message: String, expected: boolean, actual: boolean ): void assert. Equals( message: String, expected: byte, actual: byte ): void assert. Equals( message: String, expected: char, actual: char ): void Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved. 20 -44
List of assert. Equals Methods assert. Equals( expected: char, actual: char ): void assert. Equals( message: String, expected: short, actual: short ): void assert. Equals( message: String, expected: int, actual: int ): void assert. Equals( message: String, expected: Object, actual: Object ): void assert. Equals( message: String, expected: String, actual: String ): void assert. Equals( message: String, expected: double, actual: double, delta: double ): void 20 -45 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Null Test Methods • These methods can be used to test if an object is null or not null assert. Not. Null( object: Object ): void assert. Not. Null(message: String, object: Object): void assert. Null( object: Object ): void assert. Null( message: String, object: Object ): void 20 -46 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Methods to Test If Same Object assert. Not. Same( expected: Object, actual: Object ): void assert. Not. Same( message: String, expected: Object, actual: Object ): void assert. Same( message: String, expected: Object, actual: Object ): void 20 -47 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Methods to Test a Condition assert. True( message: String, condition: boolean ): void assert. True( condition: boolean ): void assert. False( message: String, condition: boolean ): void assert. False( condition: boolean ): void 20 -48 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
The Test. Case Class <<interface>> Test <<command>> Test. Case name run() Assert • It uses the command pattern to encapsulate a request to run a test case. • It is an abstract class. • All concrete test cases are derived from Test. Case. • It inherits from Assert and implements Test. 20 -49 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Test. Case Uses Template Method Template method defines a template for the algorithm, letting subclasses to implement some of the steps. <<interfaced>> Test <<command>> Test. Case name run() #set. Up() run. Test() #tear. Down() Assert <<template method>> run() { set. Up(); run. Test(); tear. Down(); } Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved. 20 -50
Collecting Test Results Test results are collected by passing a Test. Case object to Test. Result using the collecting <<sync>> parameter pattern. {f. Run. Tests++; } <<command>> <<coll. para. >> Test. Case { result. start. Test(this); set. Up(); run. Test(); tear. Down(); } Test. Result f. Run. Tests: int name start. Test (test. Case) Test. Result() run(result) #set. Up() run. Test() #tear. Down() {f. Run. Tests= 0; } 20 -51 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Collecting Test Results • public class Test. Result extends Object { protected int f. Run. Tests; public Test. Result() { f. Run. Tests= 0; } } public void run(Test. Result result) { // of Test. Case result. start. Test(this); set. Up(); run. Test(); tear. Down(); 20 -52 } Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Catching Failures and Errors public void run(Test. Result result) { result. start. Test(this); set. Up(); try { run. Test(); } catch (Assertion. Failed. Error e) { // catch anticipated failure result. add. Failure(this, e); } catch (Throwable e) { // catch unanticipated error result. add. Error(this, e); } finally { tear. Down(); } } 20 -53 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Using Adapter and Pluggable Selector public class Simple. Test extends Test. Case { public void test. Divide. By. Zero() {int zero= 0; int result= 8/zero; } public static Test suite() { Test. Suite suite= new Test. Suite(); suite. add. Test(new Simple. Test ("test. Divide. By. Zero") { protected void run. Test() { test. Divide. By. Zero(); } }); return suite; } } public class Simple. Test extends Test. Case { public void test. Divide. By. Zero() { int zero= 0; int result= 8/zero; } public void test. Add() { double result= 2+3; assert. True(result == 6); } public static Test suite() { return new Test. Suite (Simple. Test. class); } } 20 -54 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Using Adapter public class Simple. Test extends Test. Case { public void test. Divide. By. Zero() {int zero= 0; int result= 8/zero; } public static Test suite() { Test. Suite suite= new Test. Suite(); suite. add. Test(new Simple. Test ("test. Divide. By. Zero") { protected void run. Test() { test. Divide. By. Zero(); } }); return suite; } } • The adapter adapts the method that implements a test case to the required run. Test () interface. • It is an anonymous inner class. Test. Case Simple. Test Adapter 20 -55 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Using Pluggable Selector public class Simple. Test extends Test. Case { public void test. Divide. By. Zero() { int zero= 0; int result= 8/zero; } public void test. Add() { double result= 2+3; assert. True(result == 6); } public static Test suite() { return new Test. Suite (Simple. Test. class); } } • pluggable selector stores a method name in an instance variable, i. e. , f. Name in Test. Case. • JUnit then uses Java reflection to invoke the method using f. Name. • On the left, JUnit simply invokes all methods begin with "test" in the name. 20 -56 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
Test. Suite Is a Composite 20 -57 Copyright {c} 2014 by the Mc. Graw-Hill Companies, Inc. All rights Reserved.
- Slides: 57