Overview

Milton is a part test framework and utility and part methodology. It is comprised of a three parts.

The Basics

The main idea behind Milton is to make it easier and faster to write end-to-end tests for the Beehive Controls framework. We want to be able to verify that all features Controls work in the two Control client contexts in Beehive: Java Page Flows (JPF) and the JSR-181 implementation of Java Web Services (JWS). "Note: Jave Web Services in Beehive are called Web Services Metadata (WSM) but use the .jws file extension." To accomplish this we have broken the tests into four pieces.

A Controls test using Milton will run in the following order.

Writing Controls Tests

There are two main ways to write tests using Milton though in the end they have the same pieces. The difference is in which of the four pieces you need ot provide.

Using Milton Client Generation

This is the recommended way for writing Controls tests. It is the the easiest and most efficient way of running end-to-end Controls tests. Using Client Generation you need only write the Control(s) needed for testing and the Driver which excercises the test control(s). Drivers are basically POJO which look similar to JUnit test cases with a few minor differences.

Here is an example Driver:

import org.apache.beehive.test.tools.milton.common.Report;
import org.apache.beehive.test.tools.milton.annotations.Milton;

import org.apache.beehive.controls.test.controls.instantiate.InstantiateControlBean;

@Milton.TestSuite
public class InstantiationDriver
{
        @Milton.Test
        public Report testInstantiation(InstatiateControlBean icb){

                Report report = new Report();

                if (icb == null) {
                        report.setStatus(Report.FAIL);
                        report.addMessage("InstantiateControlBean hcb is Null!");
                }
                else
                {
                        if (icb.echoString("hello").equals("hello"))
                                report.setStatus(Report.PASS);
                        else {
                                report.setStatus(Report.FAIL);
                                report.addMessage("icb.echoString: " + icb.echoString("hello"));
                        }
                }
                return report;
        }

}

public SomeControlBean<String> testMethodName_scb;}}}

Using Milton without Client Generation

There will be cases when the limitations in the Client Generation will impare your ability to write tests (it is generating code after all - we can't read your mind and anticipate 'all' posibilty testing scearios) or you may just prefer to write all the parts yourself. This section will describe the parts you'll need to write and provide descriptions. For those who are using Client Generation this section will be useful if you wish to understand what is generated for your tests to run.

JPF Client Example:

import org.apache.beehive.netui.pageflow.PageFlowController;
import org.apache.beehive.netui.pageflow.Forward;
import org.apache.beehive.netui.pageflow.annotations.Jpf;

import org.apache.beehive.controls.api.bean.Control;

import org.apache.beehive.controls.test.controls.instantiate.InstantiateControlBean;
import org.apache.beehive.controls.test.driver.instantiate.InstantiationeDriver;

import org.apache.beehive.test.tools.milton.common.Report;

@Jpf.Controller(
forwards = { @Jpf.Forward(name=Report.RESULTS,path = Report.RESULTSJSP) } 
)
public class Controller extends PageFlowController
{
    @Control
    public InstantiateControlBean icb;
    
    @Jpf.Action
    protected Forward begin()
    {
        return new Forward(Report.RESULTS, Report.KEY, new 
        Report(Report.ABORT,"begin() is not a test method!"));
    }
    
    @Jpf.Action
    public Forward testInstantiation()
    {
       Report report = new Report()
       InstantiationDriver id = new InstantiationDriver();
       report = id.testInstantiation(icb); 
       return new Forward(Report.RESULTS, Report.KEY, report);
    }
}

If you have questions about the JPF syntax please set the NetUI documentation. In the above example there are two 'Actions'. The first is the begin() Action which is required on every JPF. In this case the begin() Action does not contain a test and puts an Report with an ABORT status on the request. Because Milton must relies on the data found in the Report obejct to analyzet he results of a test this is accomplised with JPF but putting the Report on the request and giving it a known name, Report.KEY and 'Forwarding' the user to a known JSP, Report.RESULTS. Using Report.RESULTS and Report.KEY is required for correct Milton operation because the Report must be forwarded to a JSP which converts the Report to an HTML table which can be parsed by the JUnit accessor. THis will be true of all Actions which execute test code you want analyzed. (The Milton JSPs are copied into your webapp at build time. See ControlsTestWebApps) The second action is testInstantiation() which creates a Report, instantiates a Driver, invokes the testInstantiation(InstantiationControlBean icb) method on the Driver, and returns the results by putting the Report on the request using the Forward. Again, the scope of this doc is not to explain JPF so if the JPF doesn't make sense please see the NetUI documentation. To correctly use Milton to test your controls you will need to mimic the above Action. Also note, this test uses the Declarative Instantiation to instantiate the test control. If you want to use Programatic Instantiation please Controls documentation.

JWS Client Example:

package milton.webservices.instantiate;

import javax.jws.WebMethod;
import javax.jws.WebService;

import org.apache.beehive.controls.test.controls.instantiate.InstantiateControlBean;
import org.apache.beehive.controls.test.driver.instantiate.InstantiationDriver;

import org.apache.beehive.test.tools.milton.common.Report;

import org.apache.beehive.controls.api.bean.Control;

@WebService
public class InstantiationDriverWebService
{
    @Control
    public InstantiationControlBean icb;
      
    @WebMethod
    public Report testInstantiation() throws Exception
    {
        InstantiationDriver id = new InstantiationDriver();
        return id.testInstantiation(icb);
    }
}

If you have questions about the JWS syntax please refer to the WSM documentation. This should look similar to the JPF example above with a few minor changes. In this case there is a WebMethod called testInstantiate() which can directly return a Report to the JUnit accessor. Also note that when using Milton your WebMethod must take no parameters as the Milton test clients have no mechanism to pass data to the JWS. In other words, your tests must be self contained as much as possible so that they can easily be moved from one client context to another.

JUnit Accessor Examples:

import org.apache.beehive.test.tools.milton.junit.HtmlReportTestCase;

import org.apache.beehive.test.tools.mantis.annotations.tch.*;

public class TestInstantiation extends HtmlReportTestCase
{
    public TestInstantiation(String s){super(s);}
    
    @Freq("checkin")
    @Status("active")
    public void testInstantiation() throws Exception
    {
        assertReport("/controlsWeb/milton/pageflows/instantiate/InstantiationDriver/testInstantiation.do");
    }
}

JPF Accessors like the one above must extend HtmlReportTestCase to take advantage of the assertReport methods. The String passed to assertReport is the path relative to the root to the JPF which contains your test. (You can put in a fully qualified URL here if you prefer but Milton can discover the name of your host) Here we take advantage of the JPF 'actionName.do' syntax. The annotations @Freq and @Status are used for creating TCH files. You are highly encouraged to use TCH as it helps to organize the test base. For more information on TCH please see the TCH documentation.

import org.apache.beehive.test.tools.milton.junit.SOAPReportTestCase;

import org.apache.beehive.test.tools.mantis.annotations.tch.*;

public class TestInstantiation extends SOAPReportTestCase
{
    public TestInstantiation(String s){super(s);}
    
    @Freq("checkin")
    @Status("active")
    public void testInstantiation() throws Exception
    {
        assertReport("/controlsWeb/milton/webservices/instantiate/InstantiationDriverWebService.jws", "testInstantiation");
    }
}

The above is quite similar to the JPF accessor example. Here the accessor extends SOAPReportTestCase which contains code to deserialize the Report returned by the testInstantiation() Web Method. The Report is then inspected for the test status (PASS,FAIL,ABORT), for any messages that were added to the Report, and any exceptions that were attached.

In both examples, the test method (WebMethod and Action) names are all the same. This helps trace which methods are associated with each other. This convention is not required but is definitly encouraged. When using Client Generation you will get tests generated which look very similar to the above examples (JPF, JPF, JUnit Accessors).

Controls/TestingControls/Milton (last edited 2009-09-20 23:24:28 by localhost)