'Illegal attempt to call getOutputStream() after getWriter() has already been called'在泽西测试期间



我有一个Jersey端点,我想测试。

端点:

@Path("image")
class ImageResource {
    @Inject
    private ImageService imageService;
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response save(ImageVO imageVO) {
        imageVO = imageService.save(imageVO);
        ResponseVO responseVO = new ResponseVO(true, imageVO);
        return Response.status(Response.Status.CREATED).entity(responseVO).build();
    }
}
测试:

class ImageResourceTest extends JerseyTest {
    private static final String BASE_ENDPOINT = "rest";
    private static final String IMAGE_ENDPOINT = "image";
    @Mock
    private ImageService imageService;
    @InjectMocks
    private ImageResource imageResource;
    @Override
    protected URI getBaseUri() {
        return UriBuilder.fromUri(super.getBaseUri()).path(BASE_ENDPOINT).build();
    }
    @Override
    protected Application configure() {
        MockitoAnnotations.initMocks(this);
        ResourceConfig config = new ResourceConfig();
        config.register(imageResource);
        return config;
    }
    @Test
    public void testSave() {
        ImageVO imageVO = new ImageVO();
        imageVO.setId("TEST");
        when(imageService.save(imageVO)).thenReturn(imageVO);
        Entity e = Entity.entity(imageVO, MediaType.APPLICATION_JSON);
        Response response = target().path(IMAGE_ENDPOINT).request().post(e, Response.class);
        assertEquals(201, response.getStatus());
        ResponseVO responseVO = response.readEntity(ResponseVO.class);
        assertTrue(responseVO.isSuccess());
    }
}

和例外:

Jul 13, 2015 9:14:28 AM org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory$GrizzlyTestContainer start
INFO: Starting GrizzlyTestContainer...
Jul 13, 2015 9:14:28 AM org.glassfish.grizzly.http.server.NetworkListener start
INFO: Started listener bound to [localhost:9998]
Jul 13, 2015 9:14:28 AM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
Jul 13, 2015 9:14:28 AM org.glassfish.jersey.server.ServerRuntime$Responder process
SEVERE: Error occurred when processing a response created from an already mapped exception.
InboundJaxrsResponse{ClientResponse{method=POST, uri=http://localhost:9998/rest/image, status=500, reason=Request failed.}}
Jul 13, 2015 9:14:28 AM org.glassfish.jersey.server.ServerRuntime$Responder release
WARNING: Attempt to release request processing resources has failed for a request.
java.lang.IllegalStateException: Illegal attempt to call getOutputStream() after getWriter() has already been called.
    at org.glassfish.grizzly.http.server.Response.getNIOOutputStream(Response.java:621)
    at org.glassfish.grizzly.http.server.Response.getOutputStream(Response.java:646)
    at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer$ResponseWriter.writeResponseStatusAndHeaders(GrizzlyHttpContainer.java:265)
    at org.glassfish.jersey.server.ServerRuntime$Responder$1.getOutputStream(ServerRuntime.java:561)
    at org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:200)
    at org.glassfish.jersey.message.internal.CommittingOutputStream.flushBuffer(CommittingOutputStream.java:305)
    at org.glassfish.jersey.message.internal.CommittingOutputStream.commit(CommittingOutputStream.java:261)
    at org.glassfish.jersey.message.internal.CommittingOutputStream.close(CommittingOutputStream.java:276)
    at org.glassfish.jersey.message.internal.OutboundMessageContext.close(OutboundMessageContext.java:835)
    at org.glassfish.jersey.server.ContainerResponse.close(ContainerResponse.java:411)
    at org.glassfish.jersey.server.ServerRuntime$Responder.release(ServerRuntime.java:667)
    at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:438)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:265)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:319)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1028)
    at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:363)
    at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:217)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    at java.lang.Thread.run(Thread.java:619)
Jul 13, 2015 9:14:28 AM org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory$GrizzlyTestContainer stop
INFO: Stopping GrizzlyTestContainer...
Jul 13, 2015 9:14:28 AM org.glassfish.grizzly.http.server.NetworkListener shutdownNow
INFO: Stopped listener bound to [localhost:9998]
这个问题我已经绞尽脑汁好几天了,但就是找不到解决办法。我用同样的方法测试了多个端点,它们都没有这个问题。我使用的是java6u5的Jersey 2.6

我不知道,我无法用您提供的内容重现确切的问题(尽管我确实得到一些错误)。我将发布我的测试,也许你可以弄清楚。

我做的主要改变是:

    只是使用Jersey的注入框架来处理DI。你可以看到下面的config.register(new AbstractBinder()。点击这里查看更多信息
  • 将Mock的when移动到配置点,而不是在测试方法中。

如果你仍然不能让它工作,试着用我提供的依赖项和一个测试用例创建一个新项目。如果有用,那就是你没有给我们看的东西,这可能就是问题所在。如果你想提供一个重现这个问题的小Github项目,我可以看看。

Maven依赖

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
        <version>2.6</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.4.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.9.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
</dependencies>
测试用例

import java.net.URI;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.junit.Assert.*;
import org.mockito.Mockito;
import static org.mockito.Mockito.when;
public class ImageServiceTest extends JerseyTest {
    private static final String BASE_ENDPOINT = "rest";
    private static final String IMAGE_ENDPOINT = "image";
    private static final ImageVO imageVO = new ImageVO("Test");
    public static interface ImageService {
        ImageVO save(ImageVO imageVo);
    }
    public static class ImageVO {
        public String id;
        public ImageVO() {}
        public ImageVO(String id) { this.id = id; }
    }
    public static class ResponseVO {
        public boolean cool;
        public ImageVO imageVo;
        public ResponseVO() {}
        public ResponseVO(boolean cool, ImageVO imageVo) {
            this.cool = cool; this.imageVo = imageVo;
        }
    }
    @Path("image")
    public static class ImageResource {
        @Inject
        private ImageService imageService;
        @POST
        @Produces(MediaType.APPLICATION_JSON)
        @Consumes(MediaType.APPLICATION_JSON)
        public Response save(ImageVO imageVO) {
            imageVO = imageService.save(imageVO);
            ResponseVO responseVO = new ResponseVO(true, imageVO);
            return Response.status(Response.Status.CREATED).entity(responseVO).build();
        }
    }
    @Override
    public Application configure() {
        final ImageService imageService = Mockito.mock(ImageService.class);
        when(imageService.save(imageVO)).thenReturn(imageVO);
        ResourceConfig config = new ResourceConfig();
        config.register(JacksonJsonProvider.class);
        config.register(ImageResource.class);
        config.register(new AbstractBinder(){
            @Override
            protected void configure() {
                bind(imageService).to(ImageService.class);
            }
        });     
        return config;
    }
    @Override
    protected URI getBaseUri() {
        return UriBuilder.fromUri(super.getBaseUri()).path(BASE_ENDPOINT).build();
    }
    @Test
    public void testSave() {
        Entity e = Entity.entity(imageVO, MediaType.APPLICATION_JSON);
        Response response = target().path(IMAGE_ENDPOINT).request().post(e, Response.class);
        assertEquals(201, response.getStatus());
        ResponseVO responseVO = response.readEntity(ResponseVO.class);
        assertTrue(responseVO.cool);
        response.close();
    }
}

添加和注册ExceptionMapper允许我捕获并输出正在抛出的错误:

Unrecognized field "name" (Class com.example.ImageVO), not marked as ignorable at [Source:org.glassfish.jersey.message.internal.EntityInputStream@13b7c28; line: 1, column: 149] (through reference chain: com.example.ImageVO["name"])

这是因为我的ImageVO类有一个名为getName的公共方法,但没有name属性。POST调用ImageVO实例会导致JSON中name的键值为null,从而创建异常。

有两种分辨率:

  1. 设置Jackson的DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES属性为false
  2. 为测试中的post实体使用实际的JSON字符串:

    Entity e = Entity.entity("{"id":"TEST"}", MediaType.APPLICATION_JSON);
    Response r = target().path(IMAGE_ENDPOINT).request.post(e, Response.class);
    

相关内容

  • 没有找到相关文章

最新更新