首页 > 解决方案 > 如何在不运行服务器的情况下对 Jersey REST API 进行单元测试?

问题描述

我正在使用一个 REST API,它使用带有 Spring Boot 的 Jersey(因此在 XML 或 Java 中没有特定的应用程序上下文)和 Spring Data JPA。

我想在 GET 和 POST 端点上编写单元测试,但是,我不想启动 Web 服务器,因为它需要太长时间。

如果我使用JerseyTest我的 Spring Bean,则不会将其加载到上下文中。

public class InMemoryContainerPackageTest extends 
        JerseyTestNg.ContainerPerClassTest {

  @Override
  protected TestContainerFactory getTestContainerFactory() {
    return new InMemoryTestContainerFactory();
  }

  @Override
  public Application configure() {
    ResourceConfig config = new ResourceConfig()
                              .register(SpringLifecycleListener.class)
                              .register(RequestContextFilter.class)
                              .register(this)
                              .register(MyController.class)
                              .packages("com.my.service");
    return config;
  }

如果我使用SpringBootTest它启动一个大约需要 30 秒的 Web 服务器,理想情况下我希望我的所有测试在 5 秒内完成,否则开发人员将不会运行它们。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestNGClass1 extends AbstractTestNGSpringContextTests {

我认为不适MockMvc用于泽西端点。

标签: spring-bootjerseytestng

解决方案


如果我使用JerseyTest我的 Spring Bean,则不会将其加载到上下文中。

您可以做的是"contextConfig"在您的ResourceConfig. 该值将是一个 SpringApplicationContext实例。因此,如果您使用 Java 配置,则只需使用AnnotationConfigApplicationContext.

@Override
public ResourceConfig configure() {
    return new ResourceConfig()
            .register(TestResource.class)
            .property("contextConfig",
                    new AnnotationConfigApplicationContext(SpringConfig.class));
}

这里,SpringConfig是一个任意的 Spring@Configuration类。下面是一个完整的例子。

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.assertj.core.api.Assertions.assertThat;


public class SpringTest extends JerseyTest {

    public static class MessageService {
        public String getMessage() {
            return "Hello World";
        }
    }

    @Configuration
    public static class SpringConfig {
        @Bean
        public MessageService service() {
            return new MessageService();
        }
    }

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

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

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig()
                .register(TestResource.class)
                .property("contextConfig",
                        new AnnotationConfigApplicationContext(SpringConfig.class));
    }

    @Override
    public TestContainerFactory getTestContainerFactory() {
        return new InMemoryTestContainerFactory();
    }

    @Test
    public void testIt() {
        Response res = target("test")
                .request()
                .get();

        String msg = res.readEntity(String.class);
        System.out.println(msg);
        assertThat(msg).isEqualTo("Hello World");
    }
}

至于 JPA,您将不得不自己配置它。使用 Spring Boot 时,所有的 JPA 引导都会得到处理。如果您打算使用 Jersey 测试框架,那么您将忽略所有 Spring Boot 配置。

自己配置 JPA 真的没那么难。它基本上包括配置 a DataSource、 a TransactionManager、 aJpaVendorAdaptor和 a LocalContainerEntityManagerFactoryBean。要启用 Spring Data 存储库,您只需使用@EnableJpaRepositories.

看看这个完整的示例配置

另一件需要注意的事情是,当我们使用 Jersey 测试框架时,我们不会像使用 Spring Test 那样获得测试范围的事务(和回滚)。因此,当您编写测试时,您需要考虑到这一点。


推荐阅读