Java 基于JerseyExtension的测试,JUnit5在请求之间不保持会话

Java 基于JerseyExtension的测试,JUnit5在请求之间不保持会话,java,jersey,junit5,jersey-test-framework,Java,Jersey,Junit5,Jersey Test Framework,我使用JerseyExtension()和JUnit5进行了一个自包含的Jersey测试(因为JerseyTest不能与JUnit5一起工作,除非您使用vintage引擎),随后对容器的调用将获得不同的会话。有没有办法在两次调用之间保持会话存储相同 package com.test.jerseysession; import com.github.hanleyt.JerseyExtension; import org.glassfish.jersey.client.ClientConfig;

我使用JerseyExtension()和JUnit5进行了一个自包含的Jersey测试(因为JerseyTest不能与JUnit5一起工作,除非您使用vintage引擎),随后对容器的调用将获得不同的会话。有没有办法在两次调用之间保持会话存储相同

package com.test.jerseysession;

import com.github.hanleyt.JerseyExtension;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import static org.junit.jupiter.api.Assertions.assertNotNull;

public class JerseyTestWithGrizzly {
    private final static TestContainerFactory testContainerFactory;
    private final ServletContainer servletContainer;
    private final ResourceConfig resourceConfig;
    private final DeploymentContext deploymentContext;

    static {
        testContainerFactory = new GrizzlyWebTestContainerFactory();
    }

    @RegisterExtension
    @SuppressWarnings("unused")
    JerseyExtension jerseyExtension = new JerseyExtension(
            this::getTestContainerFactory,
            this::configureDeploymentContext,
            this::configureJerseyClient);

    public JerseyTestWithGrizzly() {
        this.resourceConfig = new ResourceConfig()
                .packages("com.test.jerseysession")
                .register(getClass());

        this.servletContainer = new ServletContainer(resourceConfig);

        this.deploymentContext = ServletDeploymentContext.builder(resourceConfig)
                .servlet(servletContainer)
                .servletPath("api")
                .build();
    }    

    @Path("session")
    public static class SessionResource {
        @GET
        public String get(@Context HttpServletRequest request) {
            HttpSession session = request.getSession(true);
            Object obj = session.getAttribute("name");
            return session.getId() + ": " + obj;
        }

        @PUT
        public String put(@Context HttpServletRequest request) {
            HttpSession session = request.getSession(true);
            session.setAttribute("name", "foo");
            return session.getId()+": Set name attribute called";
        }
    }

    protected ClientConfig configureJerseyClient(ExtensionContext extensionContext, ClientConfig clientConfig) {
        assertNotNull(extensionContext);
        assertNotNull(clientConfig);
        return clientConfig;
    }

    protected DeploymentContext configureDeploymentContext(ExtensionContext extensionContext) {
        assertNotNull(extensionContext);
        return deploymentContext;
    }

    protected TestContainerFactory getTestContainerFactory(ExtensionContext extensionContext) {
        assertNotNull(extensionContext);
        return testContainerFactory;
    }

    @Test
    public void testSessionSet(WebTarget target) {
        // Call PUT which sets attribute called 'name'
        Response response0 = target.path("session").request().put(Entity.entity("{}", MediaType.APPLICATION_JSON_TYPE));
        System.out.println("PUT:  status="+response0.getStatus()+" response="+response0.readEntity(String.class));

        // Call GET which should be able to find 'name' in session set by previous call
        Response response1 = target.path("session").request().get();
        System.out.println("GET:  status="+response1.getStatus()+" response="+response1.readEntity(String.class));
    }
}
样本输出:

PUT:  status=200 response=8373522406385125383: Set name attribute called
GET:  status=200 response=8264425692811867393: null

会话ID在调用PUT和GET之间发生了更改。

Jersey测试框架使用的客户端在设置Cookie/Cookie头时的行为与浏览器不同。这两个请求未连接,第一个响应设置的JSESSIONID不会传播到下一个请求。虽然框架知道JSSessionID(如果存在),但它不跨请求,需要手动向前复制

将试验方法更改为以下工作:

@Test
public void testSessionSet(WebTarget target) {
    Response response0 = target.path("session").request().put(Entity.entity("{}", MediaType.APPLICATION_JSON_TYPE));
    System.out.println("PUT:  status="+response0.getStatus()+" response="+response0.readEntity(String.class));

    Invocation.Builder nextRequestBuilder = target.path("session").request();
    NewCookie jsessionid = response0.getCookies().get("JSESSIONID");
    if (jsessionid != null) {
        nextRequestBuilder.cookie(jsessionid);
    }
    Response response1 = nextRequestBuilder.get();
    System.out.println("GET:  status="+response1.getStatus()+" response="+response1.readEntity(String.class));
}

它是决定注入参数生命周期的扩展。请显示扩展的resolveParameter方法,该方法可能必须更改。是扩展名,我将检查代码,看看是否能找出它在哪里解析。@johanneslink