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

  • Published on

  • View

  • Download


Java tools for XP(Testing your Web App)Web Apps and ServicesAgendaIntroductionAntJunitInside JunitHow to write Test CaseTesting WebappTesting Non Functional Req.ConclusionIntroductionXP VS RUPHeavy VS AgileCommon SenseIterative & incrementalTest emphasisIs Safe..? Unit DevelopIntegrationTestSafe with Automatic TestUnit DevelopIntegrationTestJunitCactusHttpUnit Jmeter JunitPerfMotivation of AntModern team-based, cross-platform developmentDevelopers/users have different environments: c:\jdk1.3, d:\jdk1.3, c:\jdk1.2.2 Differences between user andDevelopers may prefer different IDEs IntelliJ, JBuilder, EmacsUsers may not have any IDE at all.Frequent releases and distributions.AntAnalogous to make in UnixFor Continuous integrationCross-platform Extensible Open source Defacto standard for Java projectsAnt and J2EEWhy needed in J2EEMany source, many targetJar, war, earDifferent Server configurationGood reference with J2EE EJB Design Patterns Java Tools for Extreme ProgrammingJUnitJava Unit test libraryMinimizes delay between bug creation, detection and correctionProven to increase team productivityProvides regular, concrete feedback to project managers and sponsors And development teamMakes testing quick and simpleBecause testable code is better codeRun()public abstract class TestCase implements Test { private final String fName; public TestCase(String name) { fName= name; } public abstract void run(); }Template Methodpublic void run() { setUp(); runTest(); tearDown(); }protected void runTest() { } protected void setUp() { } protected void tearDown() { }TestResultpublic 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(); } }TestCaseprotected 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();; } }Complete StructureHow to TestStep 1: Write A Test Case Step 2: Write A Test Suite Step 3: Organize The TestsStep 4: Run The TestsWrite 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[]) {;} Write A Test SuiteDefine 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 modeSuite() public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(ShoppingCartTest.suite()); suite.addTest(CreditCardTestSuite.suite()); return suite; }organizeCreate 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 testsDefine similar TestSuite classes that create higher-level and lower-level test suites in the other packages of the application. SampleAllTests (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 ThreadPoolTestCaseOur SituationWEB!!Approchs to testing webappsRequest-ResponseExercise code by issuing HTTP requests and examining the responsesIn-containerExercise code from within the container itselfNo-containerExercise code without going through a containerRequest-ResponseIntuitive and easy to get startedCan be hard to maintain without frequent test refactoring, verification of HTML content can be convolutedApplicable to most situations, widely used for acceptance testsIn 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 differencesNo ContainerTests run quickly and in isolationHard to test JSPs, not indicative of in-container results Tools and FrameworksRequest- ResponseHttpUnit (sourceforge. net): tests defined in codeJMeter (jakarta): performance and stress testingIn- containerCactus (jakarta)No- containerMockObjects (sourceforge. net)CactusJunit is not sufficient with J2EEHow can I get information from Session, request,response.Extension of jUnit for J2EEServletTestCaseFilterTestCaseJspTestCaseSequenceArchitecturebeginXXX(WebRequest request){}testXXX(){}endXXX(WebResponse response){}setup(){}tearDown(){}Sample TestbeginRequestResponse(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 Testpublic void testXXX(){ SampleServlet servlet = new SampleServlet(); session.setAttribute("name", "value"); String result = servlet.doSomething(request); assertEquals("something", result); assertEquals("otherValue", session.getAttribute("otherName"));}HttpUnitFor Functional TestWeb Client Maintain stateSend requestRetrive responseMethods that simplify verification of responseSample 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 TestIs run correctly?Non Functional TestResponse TimeActive UserTransaction per SecondJmeterProfilingJunitPerfPerfermance Testing ExtensionDecoratersTimed TestLoadTestThreadedTestTimed Testpublic 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 Testpublic 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 OptimizationDon't optimize as you gomaking sure that the code is clean, correct, and understandableRemember the 80/20 ruleuse profiling to find out where that 80% of execution time is goingAlways run "before" and "after" benchmarksIf slightly faster undo your changes and go back to the originalUse the right algorithms and data structuresTesting PrincipleThe 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.ConclusionJunitBean,EJBCactusServlet JSPHole AppHttpUnitConclusion (cont.)Hold App80%20%JMeterJunitPerfresourceAnt(


View more >