Saturday 3 August 2013

12:testing Framework

Learning Objectives
After completing this session, you will be able to:
‰  Define JUnit Framework
‰  Identify the importance of JUnit Framework
‰  Describe JUnit mechanics
‰  List the Fixtures
‰  Identify Test Suites
‰  List Test Runners
‰  Identify JUnit classes
‰  Identify the best practice guidelines
‰  Identify the design patterns for testing
‰  List Extensions
Importance of Test
‰  Automated tests prove feature
‰  Tests retain their value over time and allow others to prove that the software still works
(as tested)).
‰  Write test cases first and then code it.
‰  Code quality is improved since the code is tested against the test cases at various
stages.
Test Driven Development
‰  TDD (Test Driven Development) is a software development technique that involves
repeatedly first writing a test case and then implementing only the code necessary to
pass the test.
‰  TDD gives rapid feedback.
Unit Testing
‰  Unit testing is a procedure used to validate that individual units of source code are
working properly.
‰  A unit is the smallest testable part of an application. In procedural programming a unit
may be an individual program, function, procedure, Web page, menu, and so on while
in object-oriented programming, the smallest unit is always a class, which may be a
base or super class, abstract class or derived or child class.
JUnit
‰  JUnit is a regression testing framework.
‰  JUnit is used by developers to implement unit tests in Java (de-facto standard)
‰  Integrated with Ant:Testing is performed as part of nightly build process
‰  Goal:Accelerate programming and increase the quality of code
‰  JUnit is a part of XUnit family testing framework
Importance of JUnit
‰  Without JUnit, you will have to use println() to print out some result:
‰  No explicit concept of test passing or failure
‰  No mechanism to collect results in a structured fashion
‰  No replicability
‰  JUnit addresses all these issues
Key Goals of JUnit
The key goals of JUnit are:
‰  Easy to use to create tests
‰  Create tests that retain their value overtime
‰  Leverage existing tests to write new ones (reusable)
Services Provided by JUnit
The services provided by JUnit are:
‰  API for easily creating Java test case
‰  Comprehensive assertion facilities
‰  Verify expected versus actual results
‰  Test runners for running tests
‰  Aggregation facility (test suites)
‰  Reporting
Guidelines for Writing Code Based on JUnit Test (Minimum)
The guidelines for writing code based on JUnit test are:
‰  Include junit.jar in the classpath
‰  Define a subclass of TestCase class
‰  Define one or more public testXxx() methods in the subclass
‰  Write assert statements inside testXxx() method
‰  Optionally define main() method to run the test case in standalone mode
Test Methods
‰  Test methods has name pattern testXxx().
‰  Xxx reflects the method of the target class.
‰  Test methods must have no arguments.
‰  Test methods are type of void.
Example 1: Very Simple Test
import junit.framework.TestCase;
public class SimpleTest extends TestCase {
public SimpleTest(String name) {
super(name);
}
// Test code
public void testSomething() {
System.out.println("About to call assertTrue() method...");
assertTrue(4 == (2 * 2));
}
// You don't have to have main() method, use Test runner
public static void main(String[] args){
junit.textui.TestRunner.run(SimpleTest.class);
}
}
Guidelines for Writing Code Based on JUnit Test (Sophisticated)
The guidelines for writing code based on JUnit test are:
‰  Optionally override the setUp() and tearDown() methods:
‰  Create common test data
‰  Optionally define a static suite() factory method
‰  Create a TestSuite containing all the tests
Example 2: More Sophisticated Example
//Define a subclass of TestCase
public class StringTest extends TestCase {
// Create fixtures
protected void setUp(){ /* run before */}
protected void tearDown(){ /* after */ }
// Add testing methods
public void testSimpleAdd() {
String s1 = new String(“abcd”);
String s2 = new String(“abcd”);
assertTrue(“Strings not equal”, s1.equals(s2));
}
// Could run the test in batch mode
public static void main(String[] args){
junit.textui.TestRunner.run (suite ());
}
// continued …
// Create TestSuite object
public static Test suite (){
suite = new TestSuite ("StringTest");
String tests = System.getProperty("tests");
if (tests == null){
suite.addTest(new TestSuite(StringTest.class));
} else {
StringTokenizer tokens = new
StringTokenizer(tests, ",");
while (tokens.hasMoreTokens()){
suite.addTest(new
StringTest((String)tokens.nextToken()));
}
}
return suite;
}
Assert Statements
‰  JUnit assertions are methods starting with the keyword assert.
‰  An assert statement determines the success or failure of a test.
‰  An assert is simply a comparison between an expected result and the actual value.
‰  Two variants are:
o  assertXxx(...)
o  assertXxx(String message, ...)
‰  The message is displayed when assertXxx() fails.
‰  assertTrue() statement asserts that the given condition is true:
o  assertTrue(boolean condition)
o  assertTrue(String message, boolean condition)
‰  assertFalse()statement asserts that the given condition is false
o  assertFalse(boolean condition)
o  assertFalse(String message, boolean condition)
‰  assertEquals()statement asserts that the expected result is equal to the actual
behavior
o  assertEquals(expected, actual)
o  assertEquals(String message, expected, actual)
‰  assertSame()statement asserts that the expected result is same as the actual
behavior
o  assertSame(Object expected, Object actual)
o  assertSame(String message, Object expected, Object actual)
‰  assertNull() statement asserts that the object reference is null
o  assertNull(Object obj)
o  assertNull(String message, Object obj)
‰  assertNotNull()statement asserts that the object reference is not null
o  assertNotNull(Object obj)
o  assertNotNull(String message, Object obj)
‰  The fail() statement forces a failure
o  fail()
o  fail(String message)
Fixtures
‰  setUp() and tearDown()methods are used to initialize and release common test data.
‰  The setUp() method is run before every test invocation and the tearDown() method is
run after every test method.
Example: setUp
public class MathTest extends TestCase {
protected double fValue1, fValue2;
protected void setUp() {
fValue1= 2.0;
fValue2= 3.0;
}
public void testAdd() {
double result= fValue1 + fValue2;
assertTrue(result == 5.0);
}
public void testMultiply() {
double result= fValue1 * fValue2;
assertTrue(result == 6.0);
}
}
Test Suites
‰  Test Suites are used to collect all the test cases
‰  Test Suites can contain testCases and testSuites:
TestSuite(java.lang.Class theClass, <java.lang.String name>)
addTest(Test test) or addTestSuite(java.lang.Class testClass)
‰  Test Suites can have hierarchy
Example: Test Suites
public static void main (String [] args){
junit.textui.TestRunner.run (suite ());
}
public static Test suite (){
suite = new TestSuite("AllTests");
suite.addTest(new TestSuite (AllTests.class));
suite.addTest(StringTest.suite());
}
public void testAllTests () throws Exception{
assertTrue (suite != null);
}
public static Test suite() {
TestSuite suite = new TestSuite(IntTest.class);
suite.addTest(new TestSuite(FloatTest.class));
suite.addTest(new TestSuite(BoolTest.class));
return suite;
}
TestRunners
Highlights of the Test Runner in text mode:
Lightweight, quick quiet
Run from command line
Example:
java StringTest
.......
Time: 0.05
Tests run: 7, Failures: 0, Errors: 0
TestRunners: Swing
Run with java junit.swingui.TestRunner:














Automating Testing (Ant)
The JUnit task is shown in the following code:
<target name="test" depends="compile-tests">
<junit printsummary="yes" fork="yes">
<classpath>
<pathelement location="${build}" />
<pathelement location="${build}/test" />
</classpath>
<formatter usefile="yes" type="plain" />
<test name="AllTests" />
</junit>
</target>
Ant Batch Mode
<target name="batchtest" depends="compile-tests">
<junit printsummary="yes" fork="yes" haltonfailure="no">
<classpath>
<pathelement location="${build.dir}" />
<pathelement location="${build.dir}/test" />
</classpath>
<formatter type="plain" usefile="yes"/>
<batchtest fork="yes" todir="">
<fileset dir="${test.dir}">
<includename="**/*Test.java" />
</fileset>
</batchtest>
</junit>
</target>
JUnit Class Diagram
























Best Practices: What Should You Test
‰  Tests things, which could break
‰  Write test case methods such thatthe testing should succeed quietly
etter methods
‰  Do not write test case methods for the compiler
‰  What should not you test
‰  Do not write test case methods for the settergetter.
Test First and What to Test
‰  Key points on Testing
‰  Write your test first, or at least at the same time
‰  Test what can break
‰  Create new tests to show bugs and then fix the bug
‰  Test driven development says write the testcase first and then make it pass by coding
to it
Testing for Exceptions
public void testExpectException()
{
String s1 = null;
String s2 = new String("abcd");
try {
s1.toString();
fail("Should see null pointer");
} catch(NullPointerException ex) {
assertTrue(true);
}
}
Test Then Fix
‰  Bugs occasionally slip through (gasp!).
‰  Write a test first, which demonstrates the error. Obviously, this test is needed.
‰  Now, fix the bug and watch the bar go green!!
‰  Your tests assure that the bug will not reappear.
Test then Refactor
‰  Once the code is written you will want to improve it.
‰  The test cases should be written keeping the following factors in mind are
performance, maintainability, and readability.
‰  Tests help you to make sure that you do not break it while improving it.
‰  Test a little, code a little, test a little, code a little...
Design Patterns for Testing
Separation of interface and implementation: Allows substitution of implementation to tests
Factory pattern:Provides abstraction of creation of implementations from the tests
Strategy pattern:Because FactoryFinder dynamically resolves desired factory, implementations
are pluggable.
Design for Testing: Factories
Allows writing tests, which can be used across multiple implementations
Promotes frequent testing by writing tests, which work against objects without requiring extensive
setUp:
“extra-container” testing
Design for Testing: Mock Objects
‰  You can use the concept of mock objects when your implementation requires a
resource that is unavailable for testing.
‰  The mock objects mock the functionality of the desired resource.
‰  For example, using the mock objects concept, the external systemor database can be
simulated.
‰  The mock objects eliminate the dependency of the external system or database
whenever these actual resources are either not available or be difficult for testing. In
these cases, the testing gets continued with the mock objects.
Testing with Resources (EJB or DB)
‰  Testing with resources use fixtures to request resource connection by factory pattern.
‰  Testing with resources also use vm args orresource bundle to drive, which factory is
used.
‰  Data initialization or clearing is handled by fixtures to preserve order independence of
tests.
JUnit Extensions
The extensions of JUnit are:
‰  JUnitReport
‰  Cactus
‰  JWebUnit
‰  XMLUnit
‰  MockObjects
‰  StrutsTestCase
JUnitReport
‰  JUnitReport is an Apache Ant extension task.
‰  This uses XML and XSLT to generate HTML.
JWebUnit
JWebUnit is a framework that facilitates creation of acceptance tests for Web applications.
XMLUnit
XMLUnit provides a XMLTestCase class, which enables assertions to be made about the content
and structure of XML:
‰  Differences between two pieces of XML
‰  Validity of a piece of XML
‰  Outcome of transforming a piece of XML using XSLT
‰  Evaluation of an XPath expression on a piece of XML

Mock Objects
‰  The goal of generic unit testing framework is to facilitate developing unit tests in the
mock object style.
‰  Mock object:"double agent" used to test the behavior of other objects
‰  Dummy object, which mimics the external behavior of a true implementation
‰  Observes how other objects interact with its methods and compares actual behavior
with preset expectations
StrutsTestCase
StrutsTestCase extends the JUnit TestCase class that provides facilities for testing code based on
the Struts framework.
You can test the following:
‰  Implementation of your action objects
‰  Mappings declarations
‰  Form beans declarations
‰  Forwards declarations
Try It Out
Problem Statement:
Write a JUnit test file for a Java source and run it using JUnit tool in SDE.
Code:
package com.testing;
import junit.framework.TestCase;
public class HelloTest extends TestCase {
public static void main(String[] args) {
junit.textui.TestRunner.run(HelloTest.class);
}
Hello hello = new Hello();
protected void setUp() throws Exception {
super.setUp();
}
// continued …

Tips and Tricks
You have got really strange ClassNotFoundExceptions with JUnit 3.7
Solution:
‰  Does your class work fine if you run the test cases using the TextRunner?
‰  If yes, then the following explanation is probably correct:
‰  The graphical test runners apply a different class loader than the text version. This
class loader uses a special list, junit/runner/excluded.properties to define, which
classes are never reloaded, and it typically contains classes such as sun.* , javax.* ,
com.sun.* , and so on.
‰  The class loader does not load files from a jar-file, and as most of the external libraries
are distributed as such, you need to either unpack your external jar, or tell the JUnit
class loader, which classes should never be reloaded.
‰  The latter is probably more sensible, so you will not have unpacked jars cluttering your
directory structure.
‰  You need to unpack the junit.jar file, and edit the excluded.properties file to add
packages like org.apache.* and org.xml.*.
‰  Then repack the junit.jar file and apply that.
‰  Here is an example of excluded.properties file:
#
# The list of excluded package paths for the TestCaseClassLoader
#
excluded.0=sun.*
excluded.1=com.sun.*
excluded.2=org.omg.*
excluded.3=javax.*
excluded.4=sunw.*
excluded.5=java.*
excluded.6=junit.*
excluded.7=oracle.*
excluded.8=org.apache.*
Summary
Testing Idioms:
‰  Keep the following things in mind when writing JUnit tests:
oThe software does well those things that the tests check.
oTest a little, code a little, test a little, code a little...
oMake sure all tests always run at 100%.
oRun all the tests in the system atleast once per day (or night).
oWrite tests for the areas of code with the highest probability of breakage.
oWrite tests that have the highest possible return on your testing investment.
oIf you find yourself debugging using System.out.println(), write a test to
automatically check the result instead
oWhen a bug is reported, write a test to expose the bug.
oThe next time someone asks you for help debugging, help them write a test.
oWrite unit tests before writing the code and only write new code when a test is
failing.
Test Your Understanding
1.State true or false for the following:
a)JUnit is a regression testing framework.
b)setUp() is run before every test invocation and tearDown() is run after every test
method.

No comments:

Post a Comment