My favorites | Sign in
Project Home Downloads Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
GettingStarted  
Getting Started with jSupervior.
Featured
Updated Feb 16, 2011 by panwei...@gmail.com

Introduction

The purpose of this tutorial is to get you started with how to use jSupervisor before I get into the details of its internal workings and how perform different kinds of tests with jSupervisor.

I have a scenario as shown in the diagram below to illustrate the use of jSupervisor. It comprises three interacting classes. It is based on a customer’s situation. I have changed the class names and context, but the scenario remains largely the same.

Never mind why we need to test the three classes individually, but suppose the three classes are developed by separate people and each need to do their own unit tests and we would need to do a final integration test. Thus, there are a total of 4 tests.

Testing App would require a mock of Authenticating. Testing Authenticating would need a mock of AuthenticationServer. The test data are very much the same. There is potential of reuse and if not, potential for duplication and wastage as each developer seeks to create a copy of their own tests and test data.

jSupervisor allows you to reuse test scenarios, test data and mocks by specifying the scenario once and automatically generating the mocks. In this case, I created a test case known as SampleIntegrationTest.java.

I have the definitions of the interfaces to the three classes which I want to perform both unit test and integration test. The members are as follows:

/** 
 * Supervisor to manage the collaboration. 
 */ 
Supervisor supervisor ; 
/** 
 * Proxy to target app. 
 */ 
iApp myApp ;  
/** 
 * Proxy to target authentication component. 
 */ 
iAuthentication myAuthentication ; 
/** 
 * proxy to target authentication server. 
 */ 
iAuthenticationServer myAuthenticationServer ; 

Next, I describe the scenario. This I do by essentially repeating the sequence diagram above in code. This is really an alternative form to express collaboration design. I recommend that once this sequence diagram is expressed in code, you can do away with the sequence diagram itself. The code takes its place. The collaboration participants are the proxies which can be attached with concrete implementations when they are available.

public void describeScenario() throws Exception { 
   supervisor.reset() ; 
   Specifier spec = supervisor.getSpecifier() ; 
                  
   myApp.start() ; 
                  
   spec.expects(myApp,true) ; 
   myAuthentication.authenticate("Mr Foo","bar"); 
                  
   spec.expects(myAuthentication,null) ; 
   myAuthenticationServer.connect("admin"); 
  
   spec.expects(myAuthentication,true) ; 
   myAuthenticationServer.authenticate("Mr Foo","bar"); 
}  

When the method describeScenario above is executed, the dynamic proxies records all the method invocations and thereby stores the invocation sequence (i.e. the sequence diagram). In this case, jSupervisor is executing in the recording/specification mode. This imvocation execution sequence can then be played back to conduct testing in the playback mode.

During testing (i.e. the payback mode), the dynamic proxies will invoke the concrete implementations if they are attached. I have a method that attaches the concrete implementation to the proxies as follows:

public void attachImplementations(MyApp pTargetApp, 
                                 MyAuthentication pTargetAuthentication, 
                                 MyAuthenticationServer pTargetAuthenticationServer) { 
   supervisor.attach(myApp, pTargetApp) ; 
   supervisor.attach(myAuthentication, pTargetAuthentication) ; 
   supervisor.attach(myAuthenticationServer, pTargetAuthenticationServer) ; 
   if(pTargetApp!=null)  
      pTargetApp.setAuthentication(myAuthentication) ; 
   if(pTargetAuthentication!=null)  
      pTargetAuthentication.setAuthenticationServer(myAuthenticationServer) ; 
}  

The describeScenario() method records the desired execution sequence. You can print the sequence using supervisor.play().

public void testScenarioDescription() throws Exception { 
   Watcher.start() ; 
   describeScenario() ; 
   supervisor.getSpecifier().print() ; 
} 

If I were to execute the scenario with one attached concrete target, jSupervisor creates the necessary mocks based on the described scenario.

public void testWithNoAttachments() throws Exception { 
   Watcher.start() ; 
   describeScenario() ; 
   attachImplementations(null,null,null) ; 
   supervisor.setEcho(true) ; 
   ExecutionState state = supervisor.play() ; 
   assertEquals(state, ExecutionState.COMPLETED); 
} 

If I were to execute the scenario with all concrete targets, jSupervisor executes the scenario and compares it wih the specified scenario.

public void testWithAllAttachments() throws Exception { 
    Watcher.start() ; 
    describeScenario() ; 
    MyApp targetApp = new MyApp() ; 
    MyAuthentication targetAuthentication = new MyAuthentication() ; 
    MyAuthenticationServer targetAuthenticationServer = new MyAuthenticationServer() ; 
    attachImplementations(targetApp,targetAuthentication,targetAuthenticationServer) ; 
    supervisor.setEcho(true) ; 
    ExecutionState state = supervisor.play() ; 
    assertEquals(state, ExecutionState.COMPLETED); 
}  

So, no you have it. By describing a scenario once with its parameters and return values, you can run both unit tests for each object, and the inegration of all the objects. This is "Write Once Test Everywhere!"

Powered by Google Project Hosting