使用 Mockito 在 Grizzly 上模拟 Jersey REST Api 运行

Mocking a Jersey REST Api running on Grizzly using Mockito

我正在测试我使用 Jersey 设置的 RESTful api。我想使用 JUnit 对其进行测试,同时 运行 将其与 Grizzly 结合使用以提供 Http 容器。

使用服务器的一般测试工作正常,即发送请求和接收响应等

api 称为 CMSApi,它有一个名为 skyService 的依赖项,我想模拟它,所以我只测试 api。 所以问题是如何将 CMSApi 注入使用 Mockito 创建的 mockSkyService 对象?相关代码如下:

Grizzly 服务器启动:

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);

}

我的JUnit调用了上面的启动方法:

@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);
}

我运行测试使用@RunWith(MockitoJUnitRunner.class).

测试中的相关对象如下:

//System Under Test
private CMSApi cmsApi;

//Mock
@Mock private static SkyService mockSkyService;

这里是调用的测试方法:

  @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 依赖项

<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>

您将需要利用 ResourceConfig,因为您需要显式注册 CMSApi,以便您可以先用模拟的 SkyService 注入它注册。它基本上看起来像

// 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);

关键是让您的资源 class 设置为注入其依赖项。更容易测试是依赖注入的好处之一。您可以通过构造函数注入,或者像我所做的那样通过 setter 注入,或者通过带有 @Inject 注释的注入框架注入。

您可以查看更完整的示例 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,它使用 Jersey 1,但概念是相同的,您或许可以从中获得一些想法。

顺便说一句,您似乎在使用我熟悉的 Jersey 原型。因此,您显示的配置代码位于不同的 class 中。您可能不想弄乱当前的应用程序配置,所以也许您最好的选择是使用测试框架并创建一个新的配置,如我链接到的示例所示。否则您将需要一些其他方式来从测试 class 访问资源配置。或者您可以在测试 class 中设置一个新服务器,而不是在 Main class.

中启动服务器