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

查看:23
本文介绍了如何在内存中单元测试 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());
    }
}

项目源代码

问题:依赖注入返回空

推荐答案

我要解决的一些问题:

  • 您使用的是 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);
    }  
}

二:

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

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天全站免登陆