When you write service based applications, services seldom rarely function in isolation. Services may depend on other services for implementing a cohesive piece of functionality. And, of course, dependency from the implementation of one service to another would be through well-defined service contracts. In the previous chapter we saw these dependencies in the SCA world are expressed using references.
When you unit test testing a service implementation, you may or may not have the implementation of other services it depend on. For example, the implementation of the dependency may come from the same composite, in which case, when you unit test the composite all the dependencies would have been catered for. In other scenarios, implementations of the dependencies may come from extrenal composites, in which case, the references would have been promoted. In such scenarios, you may want to mock those references and verify the behaviour of the composites in terms of the references being called expected number of timesit is often desirable to mock its dependencies, particularly if those dependencies are services external to the current application.
Fabric3 provides service mocking using the mock implementation using Easymock, which we will cover in this section.
...
a special component implementation type based on EasyMock (http://www/easymock.org).
Adding Mock Functionality to Hello World
In this section we will have a look at how service mocking can be used in the Returning to the previous hello world example. Let us say each time the sayHello method is called, the component implementation will , let's change the implementation to log the call using a monitor service, whose service contract is shown below:
Code Block | ||||
---|---|---|---|---|
| ||||
public interface HelloWorldMonitor { |
...
void onHello(String name); |
...
} |
The code for the service implementation class has now is changed to incorporate the call to the above service:
import org.osoa.sca.annotations.Reference;
public class HelloWorldImpl implements HelloWorld {
@Reference protected HelloWorldMonitor monitor;
public String sayHello(String name) {
monitor.onSayHello(name);
return "Hello, " + name;
}
}
Let us say the monitor service comes from a different composite, so our service composite promotes the reference as shown below, so that it can be provided in the context in which the composite will be used as a component.
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" name="HelloWorldComposite" targetNamespace="urn:helloWorld">
<service name="helloWorldService" promote="HelloWorldComponent"/>
<reference name="monitor" promote="HelloWorldComponent/monitor"/>
<component name="HelloWorldComponent">
<implementation.java class="HelloWorldImpl"/>
</component>
</composite>
Now, when we test the above composite the monitor reference will have to be provided. However, in our integration test, rather than using a real implementation of the monitor service, we use a mock implementation using Fabric3 mock support.
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:f3
Code Block | ||||
---|---|---|---|---|
| ||||
public class HelloWorldImpl implements HelloWorld {
@Reference
protected HelloWorldMonitor monitor;
public String sayHello(String name) {
monitor.onHello(name);
return "Hello " + name;
}
}
|
The HelloWorldMonitor can be mocked in the test composite as follows:
Code Block | ||||
---|---|---|---|---|
| ||||
<composite name="TestComposite" targetNamespace="urn:fabric3.org" |
...
...> <component name="HelloWorldTest"> |
...
<f3:junit class="...HelloWorldITest"{color}/> |
...
<reference name="helloWorld" target=" |
...
HelloWorldComponent"/> |
...
</component> <component name={color:#378d00}"MockComponent"{color}> <f3:implementation.mock> HelloWorldMonitor </f3:implementation.mock> |
...
</component> |
...
<include name="HelloWorldComposite/> </composite> |
...
|
In the above, implementation.mock like junit belongs to the Fabric3 namespace and is an implementation provided by Fabric3 to support mocking service references in integration tests. The implementation takes a list of token comma-separated fully-qualified names of interfaces that need to be mocked. Note: When autowire is switched on you dont need to explictly specify all the references and target them. This would make the composite less verbose.
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:f3="urn:fabric3.org"
name="HelloWorldTestComposite"
autowire="true">
<component name="HelloWorldTest">
<f3:junit class="HelloWorldITest"/>
</component>
<component name="HelloWorldComposite">
<implementation.composite name="helloWorldComposite" scdlResource="helloWorld.composite" />
</component>
<component name="MockComponent">
<f3:implementation.mock>
HelloWorldMonitor
</f3:implementation.mock>
</component>
</composite>
Now in the test code, we can Once this is setup, the JUnit test component can be modified to use the Easymock API to verify the right number of calls are made to the monitor service by the HelloWorldImpl component being tested. import org.osoa.sca.annotations.Reference;
import junit.framework.TestCase;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
public class HelloWorldITest extends TestCase {
@Reference protected HelloWorld helloWorld;
@Reference protected IMocksControl control;
@Reference protected HelloWorldMonitor monitor;
public void testSayHello() {
Code Block | ||||
---|---|---|---|---|
| ||||
public class HelloWorldITest extends TestCase { @Reference protected HelloWorld helloWorld; @Reference protected IMocksControl control; @Reference protected HelloWorldMonitor monitor; public void testSayHello() { control.reset(); |
...
monitor.onSayHello(" |
...
Foo"); |
...
control.replay(); |
...
assertEquals("Hello |
...
Foo", helloWorld.sayHello("Fred")); |
...
control.verify(); |
...
}
}
|
Before the test is run, be sure to add Easymock as a project dependency and the Fabric3 mock extension to the runtime configuration:
Code Block | ||||
---|---|---|---|---|
| ||||
<project> <modelVersion>4.0.0</modelVersion> |
...
<dependencies>
...
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.fabric3</groupId>
<artifactId>fabric3-itest-plugin</artifactId>
<configuration>
<extensions>
<dependency>
<groupId>org.codehaus.fabric3</groupId>
<artifactId>fabric3-mock</artifactId>
<version>RELEASE</version>
</dependency>
</extensions>
<shared>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.2</version>
</dependency>
</shared>
</configuration>
</plugins>
</build>
</project>
|