Java tools for XP (Testing your Web App) Web Apps and Services

Preview:

Citation preview

Java tools for XP(Testing your Web App)

Web Apps and Services

Agenda

Introduction Ant Junit

• Inside Junit• How to write Test Case

Testing Webapp Testing Non Functional Req. Conclusion

Introduction

XP VS RUP• Heavy VS Agile

Common Sense• Iterative & incremental• Test emphasis

Is Safe..?

Unit Develop Integration

Test

Safe with Automatic Test

Unit Develop Integration

Test

Junit Cactus

HttpUnit Jmeter JunitPerf

Motivation of Ant

Modern team-based, cross-platform development Developers/users have different environments:

• c:\jdk1.3, d:\jdk1.3, c:\jdk1.2.2 Differences between user and Developers may prefer different IDEs

• IntelliJ, JBuilder, Emacs Users may not have any IDE at all. Frequent releases and distributions.

Ant

Analogous to “make” in Unix For Continuous integration Cross-platform Extensible Open source Defacto standard for Java projects

Ant and J2EE

Why needed in J2EE• Many source, many target• Jar, war, ear• Different Server configuration

Good reference with J2EE • EJB Design Patterns • Java Tools for Extreme Programming

JUnit

Java Unit test library Minimizes delay between bug creation,

detection and correction Proven to increase team productivity Provides regular, concrete feedback to project

managers and sponsors And development team

Makes testing quick and simple Because testable code is better code

Run()

public abstract class TestCase implements Test {     private final String fName;     public TestCase(String name) {         fName= name;     }     public abstract void run();         … }

Template Method

public void run() {     setUp();     runTest();     tearDown(); }

protected void runTest() { } protected void setUp() { } protected void tearDown() { }

TestResult

public void run(TestResult result) {     result.startTest(this);     setUp();     try {         runTest();     }     catch (AssertionFailedError e) { //1         result.addFailure(this, e);     }     catch (Throwable e) { // 2         result.addError(this, e);     }     finally {         tearDown();     } }

TestCase

protected void runTest() throws Throwable {     Method runMethod= null;     try {         runMethod= getClass().getMethod(fName, new Class[0]);     } catch (NoSuchMethodException e) {         assert("Method \""+fName+"\" not found", false);     }     try {         runMethod.invoke(this, new Class[0]);     }     }

public class TestSuite implements Test {     private Vector fTests= new Vector(); }public void run(TestResult result) {     for (Enumeration e= fTests.elements(); e.hasMoreElements(); ) {         Test test= (Test)e.nextElement();         test.run(result);     } }

Complete Structure

How to Test

Step 1: Write A Test Case Step 2: Write A Test Suite Step 3: Organize The Tests Step 4: Run The Tests

Write A Test Case

Define a subclass of TestCase. Override the setUp() method to initialize object(s) under test. Override the tearDown() method to release object(s) under test. Define one or more public testXXX() methods that exercise the object(s)

under test and assert expected results. Define a static suite() factory method that creates a TestSuite containing

all the testXXX() methods of the TestCase. Optionally define a main() method that runs the TestCase in batch mode.

Define a subclass of TestCase.

public class ShoppingCartTest extends TestCase {

private ShoppingCart _bookCart; private Product _defaultBook;

public ShoppingCartTest(String name) { super(name); }

Setup() & tearDown()

protected void setUp() {

_bookCart = new ShoppingCart(); _defaultBook = new Product("Extreme Programming", 23.95); _bookCart.addItem(_defaultBook);}

protected void tearDown() { _bookCart = null;}

testXXX()

public void testProductAdd() { Product newBook = new Product("Refactoring", 53.95); _bookCart.addItem(newBook); double expectedBalance = _defaultBook.getPrice() + newBook.getPrice(); assertEquals(expectedBalance, _bookCart.getBalance(), 0.0); assertEquals(2, _bookCart.getItemCount());}

public void testEmpty() { _bookCart.empty(); assertTrue(_bookCart.isEmpty());}

Suite()

public static Test suite() { // Reflection is used here to add all Test TestSuite suite = new TestSuite(ShoppingCartTest.class);

// TestSuite suite = new TestSuite(); // suite.addTest(new ShoppingCartTest("testEmpty")); // suite.addTest(new ShoppingCartTest("testProductAdd")); // suite.addTest(new ShoppingCartTest("testProductRemove")); // suite.addTest(new ShoppingCartTest("testProductNotFound")); return suite;}

Main()

public static void main(String args[]) {

junit.textui.TestRunner.run(suite());

}

Write A Test Suite

Define a subclass of TestCase. Define a static suite() factory method that creates a

TestSuite containing all the tests. Optionally define a main() method that runs the TestSuite

in batch mode

Suite()

public static Test suite() {

TestSuite suite = new TestSuite();

suite.addTest(ShoppingCartTest.suite());

suite.addTest(CreditCardTestSuite.suite());

return suite;

}

organize

Create test cases in the same package as the code under test.

For each Java package in your application, define a TestSuite class that contains all the tests

Define similar TestSuite classes that create higher-level and lower-level test suites in the other packages of the application.

Sample

AllTests (Top-level Test Suite) SmokeTestSuite (Structural Integrity Tests) EcommerceTestSuite ShoppingCartTestCase CreditCardTestSuite AuthorizationTestCase CaptureTestCase VoidTestCase UtilityTestSuite MoneyTestCase DatabaseTestSuite ConnectionTestCase TransactionTestCase LoadTestSuite (Performance and Scalability Tests) DatabaseTestSuite ConnectionPoolTestCase ThreadPoolTestCase

Our Situation

WEB!!

Approchs to testing webapps

Request-Response• Exercise code by issuing HTTP requests and examining

the responses

In-container• Exercise code from within the container itself

No-container• Exercise code without going through a container

Request-Response

Intuitive and easy to get started Can be hard to maintain without frequent test refactoring, verification of HTML content can be convoluted Applicable to most situations, widely used for acceptance

tests

In Container

Enables low level unit testing, provides access to container specifics e.g. session, config, beans, …

Best for testing complex forward / include logic, code-heavy JSPs, or verifying container implementation differences

No Container

Tests run quickly and in isolation Hard to test JSPs, not indicative of in-container

results

Tools and Frameworks

Request- Response• HttpUnit (sourceforge. net): tests defined in code• JMeter (jakarta): performance and stress testing

In- container• Cactus (jakarta)

No- container• MockObjects (sourceforge. net)

Cactus

Junit is not sufficient with J2EE• How can I get information from Session,

request,response….

Extension of jUnit for J2EE• ServletTestCase• FilterTestCase• JspTestCase

Sequence

Architecture

beginXXX(WebRequest request){}

testXXX(){}

endXXX(WebResponse response){}

setup(){}

tearDown(){}

Sample Test

beginRequestResponse(WebRequest req) throws IOException {

req.addParameter("param1",“World");

}

testRequestResponse() throws IOException {

servlet.doGet(request, response);

}

endRequestResponse(WebResponse res) throws IOException{

DataInputStream dis = new DataInputStream(

res.getConnection().getInputStream());

assertEquals(“Hello World", dis.readLine());

}

Simple Test

public void testXXX(){ SampleServlet servlet = new SampleServlet();

session.setAttribute("name", "value");

String result = servlet.doSomething(request);

assertEquals("something", result); assertEquals("otherValue", session.getAttribute("otherName"));}

HttpUnit

For Functional Test Web Client

• Maintain state• Send request• Retrive response

Methods that simplify verification of response

Sample public void testWelcomePage() throws Exception {

WebConversation conversation = new WebConversation();

WebRequest request = new GetMethodWebRequest( "http://localhost/login.htm" );

WebResponse response = conversation.getResponse( request );

WebForm forms[] = response.getForms();

assertEquals( 1, forms.length );

assertEquals( 3, forms[0].getParameterNames().length );

assertEquals( "id", forms[0].getParameterNames()[2] );

}

Test to Nonfunctional Req.

Functional Test• Is run correctly?

Non Functional Test• Response Time

• Active User

• Transaction per Second

Jmeter

Profiling

JunitPerf

Perfermance Testing Extension Decoraters

• Timed Test• LoadTest• ThreadedTest

Timed Test

public static Test suite() { TestSuite suite = new TestSuite(); long maxTime = 1000 + tolerance; Test testCase = new ExampleTestCase("testOneSecond"); Test timedTest = new TimedTest(testCase, maxTime); suite.addTest(timedTest); return suite;}

Mixed Test

public static Test suite() { int users = 1; int iterations = 10; long maxElapsedTime = 10000 + tolerance; TestSuite suite = new TestSuite(); Test testCase = new ExampleTestCase("testOneSecond"); Test repeatedTest = new RepeatedTest(testCase, iterations); Test loadTest = new LoadTest(repeatedTest, users); Test timedTest = new TimedTest(loadTest, maxElapsedTime); suite.addTest(timedTest); return suite;}

General Rules for Optimization

Don't optimize as you go• making sure that the code is clean, correct, and understandable

Remember the 80/20 rule• use profiling to find out where that 80% of execution time is going

Always run "before" and "after" benchmarks• If slightly faster undo your changes and go back to the original

Use the right algorithms and data structures

Testing Principle

The software does well those things that the tests check.

Test a little, code a little, test a little, code a little...

Make sure all tests always run at 100%. Run all the tests in the system at least once

per day (or night). Write tests for the areas of code with the

highest probability of breakage.

Testing Principle (cont.)

Write tests that have the highest possible return on your testing investment.

If you find yourself debugging using System.out.println(), write a test to automatically check the result instead.

When a bug is reported, write a test to expose the bug. The next time someone asks you for help debugging,

help them write a test. Write unit tests before writing the code and only write

new code when a test is failing.

Conclusion

Junit Bean,EJB

Cactus Servlet JSP

Hole AppHttpUnit

Conclusion (cont.)

Hold App80%

20%

JMeter

JunitPerf

resource

Ant(jakarta.apache.org/ant/) Junit(www.junit.org) Cactus(jakarta.apache.org/cactus) httpUnit(httpunit.sourceforge.net) Jmeter(jakarta.apache.org/jmeter) JunitPerf(www.clarkware.com/software/

JUnitPerf.html)