我正在使用Spring-Jersey3,无法弄清楚如何使用Spring Bean对RESTFul API进行单元测试
Controller
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()); } }
Service Interface
package com.service; public interface DataSource { public String load(); }
Service Implementation
package com.service; import org.springframework.stereotype.Repository; @Repository public class DataSourceImpl implements DataSource { @Override public String load() { return "Hello"; } }
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(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>
单元测试<<-我真的不知道如何测试
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测试框架,但你的应用程序是Jersey2.x。请参阅下面的2.x依赖性。
我从未使用过Jersey 1.x风格的测试框架,但对于Jersey 2.x,内存中容器不支持servlet依赖功能。有关不同的依赖性,请参见下文。
使用Jersey测试框架,你无需创建Client自己。创建了一个,我们可以简单地调用JerseyTest的target(String path)方法来取回WebTarget(Jersey 2.x,WebResource是Jersey 1.x)。
Client
JerseyTest
target(String path)
WebTarget
Jersey 2.x,WebResource
Jersey 1.x
这是一个有效的重构。
依赖关系(我仅添加了此依赖关系,并且没有删除任何东西,因为你的GitHub项目没有包含与测试相关的任何东西,如你上面的代码示例所述)
<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参数。
return ServletDeploymentContext .forServlet(new ServletContainer(new ResourceRegister())) .addListener(ContextLoaderListener.class) .initParam("contextConfig", new AnnotationConfigApplicationContext(YourSpringConfig.class)) .build();
经过几次测试,这是我发现的几件有趣的事情
一: 有了以上依赖性,即使我们不配置DeploymentContext,而只是Application configure()在中进行覆盖JerseyTest,它仍然可以正常工作。不能真正解释它,但似乎描述符仍然被使用。
DeploymentContext
Application configure()
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); } }
二: 即使我们摆脱了上面的依赖关系(灰熊)并使用了内存中的依赖关系,同样简单的先前测试仍然有效。文档说明
内存中的容器不是真实的容器。它启动Jersey应用程序,并直接调用内部API以处理由测试框架提供的客户端创建的请求。不涉及网络通信。该容器不支持servlet和其他依赖于容器的功能,但是对于简单的单元测试,它是理想的选择。
所以我不能完全确定他们指的是什么Servlet功能,因为此测试仍然有效
<dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>jersey-test-framework-provider-inmemory</artifactId> <version>2.15</version> </dependency>
我特别不明白的是这句话
"There is no network communication involved"
因为当我运行测试时,我看到一条日志
INFO: Creating InMemoryTestContainer configured at the base URI http://localhost:9998/