4

I am having a play with testing a RESTful api which I have set up using Jersey. I want to test it using JUnit while running it with Grizzly to provide the Http container.

General testing using the server works ok, i.e. sending requests and receiving responses etc.

The api is called CMSApi and it has a dependency called skyService which I would like to mock out so I'm testing just the api. So the question is how can I inject the CMSApi with a mockSkyService object created using Mockito? The relevant code is below:

Grizzly Server start up:

public static HttpServer startServer() {
    final ResourceConfig rc = new ResourceConfig().packages("com.sky");
    rc.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);

}

My JUnit calls the above start method:

@Before
public void setUpServer() throws Exception {

    // start the server and create the client
    server = Main.startServer();

    Client client = ClientBuilder.newClient();
    target = client.target(Main.BASE_URI);
}

I run the test using the @RunWith(MockitoJUnitRunner.class).

Here are the relevant objects in the test:

//System Under Test
private CMSApi cmsApi;

//Mock
@Mock private static SkyService mockSkyService;

Here is the test method calling:

  @Test
public void testSaveTile() {

    //given
    final Invocation.Builder invocationBuilder = target.path(PATH_TILE).request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);

    Tile tile = new Tile(8, "LABEL", clientId, new Date(), null);

    //when      
    Response response = invocationBuilder.post(Entity.entity(tile, MediaType.APPLICATION_JSON_TYPE));

    //then
    assertEquals(Status.OK.getStatusCode(), response.getStatus());

}

Maven dependencies

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.sky</groupId>
<artifactId>sky-service</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>sky-service</name>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

 <dependencies>
     <dependency> 
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        </dependency>        
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-bundle</artifactId>
        <type>pom</type>
        <scope>test</scope>

    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-bean-validation</artifactId>
        </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.16</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
    <!-- Dependency for Mockito -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.9.5</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <inherited>true</inherited>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.sky.Main</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

<properties>
    <jersey.version>2.15</jersey.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

raghera
  • 633
  • 12
  • 17

1 Answers1

5

You're going to need to tap into the ResourceConfig, as you will need to explicitly register the CMSApi, so that you can inject it with the mocked SkyService prior to registering. It would basically look something like

// Sample interface
public interface SkyService {
    public String getMessage();
}

@Path("...")
public class CMSApi {
    private SkyService service;
    public void setSkyService( SkyService service ) { this.service = service; }
}

// Somewhere in test code
CMSApi api = new CMSApi();
SkyServicer service = Mockito.mock(SkyService.class);
Mockito.when(server.getMessage()).thenReturn("Hello World");
api.setSkyService(service);
resourceConfig.register(api);

The key is to have your resource class set up for injection of its dependency. Easier testing is one of the benefits of dependency injection. You can inject through constructor, or through a setter as I have done, or through an injection framework with the @Inject annotation.

You can see a more complete example here, which uses the Jersey DI framework HK2. You can also see more about Jersey and HK2 here. Then example also uses the Jersey Test Framework, which I see you already have as a dependency, so you might want to leverage that. Here is another example which uses Jersey 1, but the concept is the same, and you might be able to get some ideas from it.

As an aside, it looks like you're using the Jersey archetype, which I am familiar with. So the code for the config you are showing is in a different class. You may not want to mess with the current app configuration, so maybe your best bet is to use the test framework and create a new config as seen in the example I linked to. Or else you would need some other way to access the resource config from the test class. Or you could set up a new server in the test class instead of starting the server in the Main class.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanks for your response I was able to get what I wanted. – raghera Jan 26 '15 at 22:33
  • 1
    Thanks @peeskillet for your response. I was able to get what I wanted working as per your examples. In the end I was able to: - Inject the dependency using HK2. - I extended the JerseyTest class - I created a Factory for the Mocked Service and registered it with the ResourceConfig by overriding the configure() method. The only slight difference was that I created the Mock using the Mockito annotation and wrote the stubbing code in my test case so I could make it return what was needed for the test. – raghera Jan 26 '15 at 22:40