如何在内存中进行单元测试 Spring-Jersey [英] How to in-memory unit test Spring-Jersey

查看:33
本文介绍了如何在内存中进行单元测试 Spring-Jersey的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Spring-Jersey3,但无法弄清楚如何使用 Spring bean 对 RESTFul API 进行单元测试

I'm working with Spring-Jersey3 and cannot figure out how to unit test the RESTFul API with Spring beans

控制器

package com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.service.DataSource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("test")
@Component
public class SpringController {
    @Autowired
    private DataSource datasource;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getHello() {
        return new String(datasource.load());
    }
}

服务接口

package com.service;

public interface DataSource {
    public String load();
}

服务实现

package com.service;

import org.springframework.stereotype.Repository;

@Repository
public class DataSourceImpl implements DataSource {

    @Override
    public String load() {
        return "Hello";
    }
}

ResourceRegister.java(球衣资源寄存器)

ResourceRegister.java (Jersey resource register)

package com.component;

import org.glassfish.jersey.server.ResourceConfig;
import com.controller.SpringController;

public class ResourceRegister extends ResourceConfig {

    public ResourceRegister () {
        register(SpringController.class);
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
</context-param>

<servlet>
  <servlet-name>Jersey</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
  <param-name>javax.ws.rs.Application</param-name>
  <param-value>com.component.ResourceRegister</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>Jersey</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

serviceContext.xml(应用程序上下文)

serviceContext.xml (Application Context)

<?xml version="1.0" encoding="UTF-8"?>

<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.service" />
<context:component-scan base-package="com.controller" />

</beans>

单元测试 <<-- 我真的不知道如何测试这个

Unit test <<-- I really have no Idea how to test this

public class test extends JerseyTest {
    public test() {
        super("com.service", "com.controller");
    }

    @Override
    protected AppDescriptor configure() {
        return new WebAppDescriptor.Builder("com.service","com.controller")
               .contextParam("contextConfigLocation", "classpath:serviceContext.xml")
               .contextPath("/rest")
               .servletClass("org.glassfish.jersey.servlet.ServletContainer.class")
               .initParam("javax.ws.rs.Application", "com.component.ResourceRegister")
               .build();
    }

    @Test
    public void test() {
        Client client = new Client();
        WebResource resource = client.resource("test");

        ClientResponse response = resource.post(ClientResponse.class);

        assertEquals(200, resposne.getStatus());
    }
}

项目源代码

问题:依赖注入返回 null

推荐答案

我要解决的一些问题:

  • 您正在使用 Jersey 1.x 风格的 Jersey 测试框架,但您的应用是 Jersey 2.x.请参阅下面的 2.x 依赖项.

  • You are using Jersey 1.x flavored Jersey Test Framework, but your app is Jersey 2.x. See below for 2.x dependency.

我从未使用过 Jersey 1.x 风格的测试框架,但使用 Jersey 2.x,内存容器 不支持 servlet 依赖的特性.不同的依赖见下文.

I've never used the Jersey 1.x flavored Test Framework, but with Jersey 2.x, the In-Memory container doesn't support servlet dependent features. See below for different dependency.

使用 Jersey 测试框架,您无需自己创建 Client.创建了一个,我们可以简单地调用 JerseyTesttarget(String path) 方法来取回一个 WebTarget (Jersey 2.x, WebResource 是 Jersey 1.x)

With Jersey Test Framework, you do not need to create the Client yourself. There is one created, and we can simple call JerseyTest's target(String path) method to get back a WebTarget (Jersey 2.x, WebResource is Jersey 1.x)

这是一个有效的重构.

依赖(我只添加了这个依赖,并没有取出任何东西,因为你的 GitHub 项目没有包含任何与测试相关的东西,就像你上面的代码示例那样)

Dependency (I only added this dependency, and didn't take anything out, as your GitHub project didn't include anything test related, as your code example above does)

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.15</version>
</dependency>

测试

import com.component.ResourceRegister;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.web.context.ContextLoaderListener;

public class SpringTest extends JerseyTest {

    @Override
    protected TestContainerFactory getTestContainerFactory() {
        return new GrizzlyWebTestContainerFactory();
    }

    @Override
    protected DeploymentContext configureDeployment(){
        return ServletDeploymentContext
                .forServlet(new ServletContainer(new ResourceRegister()))
                .addListener(ContextLoaderListener.class)
                .contextParam("contextConfigLocation", "classpath:applicationContext.xml")
                .build();
    }

    @Test
    public void test() {
        String response = target("test").request().get(String.class);
        Assert.assertEquals("Hello", response);
        System.out.println(response);
    }  
}

对于那些不使用 xml 上下文文件的,你可以使用一个注释配置应用程序上下文,并将其添加为一个 init 参数

For those not use an xml context file, you can use an annotation config application context, and add it as an init param

return ServletDeploymentContext
        .forServlet(new ServletContainer(new ResourceRegister()))
        .addListener(ContextLoaderListener.class)
        .initParam("contextConfig", new AnnotationConfigApplicationContext(YourSpringConfig.class))
        .build();

其他资源:

  • Jersey Test Framework Documentation
  • More examples from Test Framework source code tests. (Hint: the link I provided is for grizzly web container examples, but if you traverse back to providers, you can look at each provider and go to the test packages for examples for those providers)

所以经过几次测试后,我发现了一些有趣的事情

So after a few more test, here are a couple interesting things I discovered

有了上面的依赖,即使我们不配置DeploymentContext,只覆盖JerseyTest中的Application configure(),它仍然可以工作.无法真正解释它,但似乎描述符仍然被拾取.

With the above dependency, even if we don't configure the DeploymentContext, and just override Application configure() in the JerseyTest, it will still work. Can't really explain it, but it appears the descriptor is still picked up.

import javax.ws.rs.core.Application;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.Test;

public class SpringTest extends JerseyTest {

    @Override
    public Application configure() {
        return new ResourceConfig().packages("com.controller");
    }

    @Test
    public void test() {
        String response = target("test").request().get(String.class);
        Assert.assertEquals("Hello", response);
        System.out.println(response);
    }  
}

二:

即使我们摆脱了上述依赖(grizzly)并使用内存中的依赖,同样简单的之前的测试仍然有效.文档说明

Two:

Even if we get rid of the above dependency (grizzly) and use the in-memory dependency, the same simple previous test works. The documentation states

In-Memory 容器不是真正的容器.它启动 Jersey 应用程序并直接调用内部 API 来处理由测试框架提供的客户端创建的请求.不涉及网络通信.此容器不支持 servlet 和其他容器相关功能,但它是简单单元测试的完美选择.

In-Memory container is not a real container. It starts Jersey application and directly calls internal APIs to handle request created by client provided by test framework. There is no network communication involved. This containers does not support servlet and other container dependent features, but it is a perfect choice for simple unit tests.

所以我不完全确定他们指的是什么 Servlet 功能,因为这个测试仍然有效

So I am not completely sure what Servlet features they are referring to, as this test still works

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-inmemory</artifactId>
    <version>2.15</version>
</dependency>

我特别不明白的,是这个说法

What I don't understand in particular, is this statement

不涉及网络通信"

因为当我运行测试时,我看到了一个日志

because when I run the test, I see a log

INFO:创建在基本 URI http://localhost:9998/配置的 InMemoryTestContainer

这篇关于如何在内存中进行单元测试 Spring-Jersey的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆