简体   繁体   中英

Access springbeans in JerseyTest with Jersey2.0

I have jersey project with spring. Now My test is deriverd from JerseyTest. When I try to do

@AutoWired 
RestTemplate restTemplate;

It looks like spring is not working in jersey test. I did some research and found some links like spring_jersey but it did not work ,since I am using jersey2.0.

My code looks like

 //AbstractTest 
    package com.test;


            import javax.ws.rs.client.WebTarget;
            import javax.ws.rs.core.Application;

        import org.glassfish.jersey.client.ClientConfig;
        import org.glassfish.jersey.filter.LoggingFilter;
        import org.glassfish.jersey.jackson.JacksonFeature;
        import org.glassfish.jersey.server.ResourceConfig;
        import org.glassfish.jersey.test.JerseyTest;
        import org.glassfish.jersey.server.ServerProperties;
        import org.glassfish.jersey.server.validation.ValidationFeature;

        public abstract class AbstractTest extends JerseyTest
        {
            protected WebTarget getRootTarget(final String rootResource)
            {
                return client().target(getBaseUri()).path(rootResource);
            }

            @Override
            protected final Application configure()
            {
                final ResourceConfig application = configureApplication();

                // needed for json serialization
                application.register(JacksonFeature.class);

                // bean validation
                application.register(ValidationFeature.class);

                // configure spring context
                application.property("contextConfigLocation", "classpath:/META-INF/applicationContext.xml");

                // disable bean validation for tests
                application.property(ServerProperties.BV_FEATURE_DISABLE, "true");

                return application;
            }

            protected abstract ResourceConfig configureApplication();

            @Override
            protected void configureClient(final ClientConfig config)
            {
                // needed for json serialization
                config.register(JacksonFeature.class);

                config.register(new LoggingFilter(java.util.logging.Logger.getLogger(AbstractResourceTest.class.getName()), false));

                super.configureClient(config);
            }
        }



    package com.test;

    import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
    import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
    import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;

    //MyTest
        import java.io.FileNotFoundException;
        import java.io.FileReader;
        import java.io.IOException;

    import javax.ws.rs.client.WebTarget;
    import javax.ws.rs.core.Response;

    import org.apache.commons.io.IOUtils;
    import org.glassfish.jersey.server.ResourceConfig;
    import org.junit.Before;
    import org.junit.Test;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.MediaType;
    import org.springframework.test.web.client.MockRestServiceServer;
    import org.springframework.test.web.client.match.MockRestRequestMatchers;
    import org.springframework.web.client.RestTemplate;

    import junit.framework.Assert;

    public final class MyTest extends AbstractTest
        {

        private static final String ROOT_RESOURCE_PATH = "/testUrl";

        @AutoWired
private RestTemplate restTemplate;
        private MockRestServiceServer mockServer;


        @Before
        public void setup(){
            this.restTemplate = new RestTemplate();
            this.mockServer = MockRestServiceServer.createServer(restTemplate);
        }

        @Test
        public void testPostWithString() {

            WebTarget target = getRootTarget(ROOT_RESOURCE_PATH).path("");
            String entityBody = new String();
            entityBody = " My test data";


            final javax.ws.rs.client.Entity<String> entity = javax.ws.rs.client.Entity.entity(entityBody, "text/plain");


            mockServer.expect(MockRestRequestMatchers.requestTo(ROOT_RESOURCE_PATH)).andExpect(method(HttpMethod.POST)).andExpect(content().string(entityBody))
                    .andRespond(withSuccess("resultSuccess", MediaType.TEXT_PLAIN));


            final Response response = target.request().post(entity);
            Assert.assertNotNull("Response must not be null", response.getEntity());
            Assert.assertEquals("Response does not have expected response code", 200, response.getStatus());

            System.out.println("Response = " + response.getEntity());

            String data = response.readEntity(String.class);

            System.out.println("Response = " + data);
            if(response.ok() != null)
            {
                System.out.println("Ok");
            }
        }
    }

Update:

public class SimpleJerseyTest extends ApplicationContextAwareJerseyTest {
    private static final String ROOT_RESOURCE_PATH = "/test";

    @Override
    public void configureApplication(ResourceConfig config) {
        config.register(MyApp.class);
        config.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
    }

    @Before
    public void setUp() {
        try{
            ((ConfigurableApplicationContext)this.applicationContext).refresh();
            super.setUp();
        }catch(Exception e){

        }
    this.mockServer = MockRestServiceServer.createServer(restTemplate);
    }

    @Autowired
    private RestTemplate restTemplate;

    private MockRestServiceServer mockServer;

    @Test
    public void doitOnce() {
        WebTarget target = target(ROOT_RESOURCE_PATH);

        String entityBody = new String();

        final javax.ws.rs.client.Entity<String> entity = javax.ws.rs.client.Entity.entity(entityBody, "text/plain");


        mockServer.expect(MockRestRequestMatchers.requestTo(ROOT_RESOURCE_PATH)).andExpect(method(HttpMethod.POST)).andExpect(content().string(entityBody))
                .andRespond(withSuccess("resultSuccess", MediaType.TEXT_PLAIN));


        final Response response = target.request().post(entity);


        System.out.println("Response = " + response.getEntity());

        String data = response.readEntity(String.class);

        System.out.println("Response = " + data);
        if(response.ok() != null)
        {
            System.out.println("Ok");
        }
    }
}

I have added bean in

src/test/resources/META-INF/applicationContext.xml

<!-- Our REST Web Service client -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>

Same bean I have added in

src/main/resources/META-INF/applicationContext.xml

!-- Our REST Web Service client -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>

Instead of configuring Spring like this

application.property("contextConfigLocation", "classpath:/META-INF/applicationContext.xml");

You can instead use

application.property("contextConfig", <ApplicationContext>);

This way you can have an instance of the ApplicationContext , where you can get the AutowireCapableBeanFactory . With this, you can just call acbf.autowireBean(this) to inject the test class.

Here's what I mean. I tested it, and it works find for simple cases. Won't work well though if the beans you are trying to inject aren't singletons, as new one will be create for the test and where ever else you try to inject to in your application code

public abstract class ApplicationContextAwareJerseyTest extends JerseyTest {

    protected ApplicationContext applicationContext;

    @Override
    protected final ResourceConfig configure() {
        final ResourceConfig config = new ResourceConfig();
        configureApplication(config);

        this.applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        config.property("contextConfig", this.applicationContext);
        final AutowireCapableBeanFactory bf = this.applicationContext.getAutowireCapableBeanFactory();
        bf.autowireBean(this);
        return config;
    }

    public final ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }

    protected void configureApplication(ResourceConfig resourceConfig) {};
}

One thing I am not sure about though is how the resetting would work. I tried to add

@Before
public void setUp() throws Exception {
    ((ConfigurableApplicationContext)this.applicationContext).refresh();
    super.setUp();
}

into the abstract class, but that doesn't seem to work as expected. The test I used is as follows

public class SimpleJerseyTest extends ApplicationContextAwareJerseyTest {


    @Path("test")
    public static class SimpleResource {
        @Autowired
        private MessageService service;

        @GET
        public String getMessage() {
            return this.service.getMessage();
        }
    }

    @Override
    public void configureApplication(ResourceConfig config) {
        config.register(SimpleResource.class);
        config.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
    }

    @Before
    public void before() {
        assertEquals("Hello World", messageService.getMessage());
    }

    @Autowired
    private MessageService messageService;

    @Test
    public void doitOnce() {
        messageService.setMessage("BOOYAH");
        final Response response = target("test").request().get();
        assertEquals("BOOYAH", response.readEntity(String.class));
    }

    @Test
    public void doitTwice() {
        messageService.setMessage("BOOYAH");
        final Response response = target("test").request().get();
        assertEquals("BOOYAH", response.readEntity(String.class));
    }
}

The result I would get for the second test is that the value of the service message was the default message "Hello World" , even though I set the message to "BOOYAH" . This tells me that there is a stale service in the application, which is not the same one being injected into the test. The first test works fine though. Without resetting, the second test would work fine also, but you are left with modified services in each test, which makes the test not self-contained.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM