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

查看:93
本文介绍了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,

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

内存中的容器不是真实的容器.它启动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

不涉及网络通信"

"There is no network communication involved"

因为运行测试时,我看到一条日志

because when I run the test, I see a log

INFO: Creating InMemoryTestContainer configured at the base URI http://localhost:9998/

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

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