【问题标题】:Mock Service inside resource using jersey test framwork使用球衣测试框架模拟资源内部的服务
【发布时间】:2016-04-25 14:52:32
【问题描述】:

我有一个使用服务的 rest API 资源。 该服务有一个带参数的构造函数。 我想测试这个资源并模拟这个服务。 这个Question: How to pass parameters to REST resource using Jersey 2.5

没有帮助,因为他们使用了@Inject 而我无法使用它。 有什么建议吗?

第二个问题是如何传递参数来测试这个资源: 我的代码是:

@Path("/2/{subversion: [0-3]}/users")
public class UserResource {
    Logger log = Logger.getLogger(UserResource.class);
    private MyService service;
    public void setService(Service ser) {
        this.service = ser;
    }

@Context HttpServletRequest currentRequest;

@GET
@Produces("application/json")
public Response getUsers(@Context HttpHeaders httpHeaders, @Context UriInfo
uriInfo) {
// my function
}
}

如何传递“httpHeaders”和“UriInfo”。 我的测试如下所示:

Response response = target("/2/0/users/").request().get();
Users users = response.readEntity(Users.class);
assertNotNull(users);

【问题讨论】:

    标签: java rest unit-testing jersey-2.0 jersey-test-framework


    【解决方案1】:

    对于服务,通过构造函数或设置器注入是一种很好的做法。这使得在单元测试期间很容易模拟和传递。至于模拟,你应该使用像Mockito 这样的框架。然后你可以做类似的事情

    MyService service = Mockito.mock(MyService.class);
    when(service.getObject()).thenReturn(new Object());
    
    HttpHeaders headers = Mockito.mock(HttpHeaders.class);
    when(headers.getHeaderString("X-Header")).thenReturn("blah");
    
    UriInfo uriInfo = Mockito.mock(UriInfo.class);
    when(uriInfo.getRequestUri()).thenReturn(URI.create("http://localhost"));
    

    然后您可以在 UNIT 测试时将所有这些模拟传递给您的资源类。

    对于 INTEGRATION 测试,您不需要模拟标头或 uriinfo。实际的会被传入。但如果你愿意,你仍然可以模拟服务。这是一个例子

    public class MockServiceTest extends JerseyTest  {
    
        public static interface Service {
            String getMessage(String name);
        }
    
        @Path("message")
        public static class MessageResource {
    
            private final Service service;
    
            public MessageResource(Service service) {
                this.service = service;
            }
    
            @GET
            public String get(@QueryParam("name") String name,
                              @Context HttpHeaders headers,
                              @Context UriInfo uriInfo) {
                String nameQuery = uriInfo.getQueryParameters().getFirst("name");
                String header = headers.getHeaderString("X-Header");
                assertNotNull(nameQuery);
                assertNotNull(header);
                return service.getMessage(name);
            }
        }
    
        private Service service;
    
        @Override
        public ResourceConfig configure() {
            service = Mockito.mock(Service.class);
            return new ResourceConfig().register(new MessageResource(service));
        }
    
        @Test
        public void testIt() {
            Mockito.when(service.getMessage("peeskillet")).thenReturn("Hello peeskillet");
    
            Response response = target("message").queryParam("name", "peeskillet").request()
                    .header("X-Header", "blah")
                    .get();
            assertEquals(200, response.getStatus());
            assertEquals("Hello peeskillet", response.readEntity(String.class));
        }
    }
    

    【讨论】:

    • 感谢您的回复。关于这一点的另一个问题是,如果我的资源属性中有 @context 属性,我该怎么办?我用那个更新了我的帖子
    • 如果您正在运行单元测试,请像我上面描述的那样模拟它。如果您正在使用测试框架运行集成测试,则需要将其配置为在 servlet 容器中运行,以便注入 HttpServletRequest。 See here
    • 非测试模式下MessageResource是如何创建的?您正在使用带有单个参数的构造函数 - 在我的情况下,球衣抱怨它找不到合适的构造函数
    • @WandMaker 您可以将资源注册为实例。我想我没有考虑过非测试模式。但是如果你不想将资源注册为实例,你应该怎么做,使用依赖注入。见stackoverflow.com/documentation/jersey/7016/…。示例没有显示它,但您可以使用构造函数注入。将@Inject 放在构造函数上,而不是字段
    • @WandMaker 这是一个如何在构造函数stackoverflow.com/a/27447345/957137上使用@Inject的示例
    猜你喜欢
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多