spring - 使用 jersey 2 和 Spring 编写 "clean"集成测试 - REST

标签 spring rest integration-testing jersey-2.0 spring-test

我希望下面编写的测试用例是一个“干净”的测试,即测试后自动回滚数据库更改。

@Test
public void testUpdate(){
    ClientConfig clientConfig = new ClientConfig();
    clientConfig.register(JacksonFeature.class);
    Client client = ClientBuilder.newClient(clientConfig);
    Name name = new Name(1L,"Updated","Updated");
    Response response = client
            .target("http://localhost:8080/jersey-spring/name/").request().header("Content-type", MediaType.APPLICATION_JSON).post(Entity.json(name));
    Assert.assertTrue(response.getStatus() == 200);
}

其余服务在集成测试期间使用jetty-maven-plugin部署。我现在面临的问题是,我无法使用 spring test transactional 测试,这意味着测试后对数据库的任何状态更改都需要手动清理,这是非常麻烦的.

所以我的问题是,当使用 jersey 作为 REST 提供程序时,运行“干净”集成测试的建议方法是什么。我也尝试过使用JerseyTest,但也面临同样的问题。

由于各种原因,我无法用 Spring MVC 替换 Jersey。

更新

  1. 不涉及任何 mock 。测试是端到端的。
  2. 我喜欢接近生产配置进行集成测试,因此不使用内存数据库进行集成测试。

最佳答案

我在许多 Spring+Jersey2 项目中使用了以下配置,并且效果很好。

  • 使用 JerseyTest 并在您的测试类中扩展它
  • 使用在 REST Controller 中模拟您的服务
  • 这很重要。使用内存数据库(我更喜欢 HSQLDB )并在内存数据库中创建一个针对此的测试应用程序上下文。因此您不必担心数据完整性等问题。
  • 通过重写 JerseyTestconfigure() 方法来配置您的测试类,注入(inject)您的模拟并将 REST Controller 的任何相关服务绑定(bind)到 Jersey Context。

这是一个例子:

@Override
protected Application configure() {
    // Bind factories of classes to be mocked.
    AbstractBinder binder = new AbstractBinder() {
        @Override
        protected void configure() {
            bindFactory(MockCrawlerManagerFactory.class).to(CrawlerManager.class);
            bindFactory(MockUrlQueueServiceFactory.class).to(UrlQueueService.class);
            bindFactory(MockSitemapServiceFactory.class).to(SitemapService.class);
            bindFactory(MockCrawlerServiceFactory.class).to(CrawlerService.class);
            bindFactory(MockUrlContentServiceFactory.class).to(UrlContentService.class);
            // Other services to mock ....
        }
    };

    // This is your main Spring application
    ApplicationContext context = new AnnotationConfigApplicationContext(Bootstrap.class);

    // And create your Jersey context here, register REST controller to Jersey context
    return new ResourceConfig().registerClasses(RestController.class, JacksonJsonProvider.class, JacksonJaxbJsonProvider.class)
            .packages("com.company.foo.crawler.rest", "com.company.foo.crawler.exception").register(binder).property("contextConfig", context);
}
  • 并开始编写测试:)

示例测试:

    @Test
    public void testCreateCrawlerWithNoConfiguration() throws ExecutionException, InterruptedException {
    String mockUrl = "/version/" + VERSION + "/crawlers";
    Map<String, Object> data = new HashMap<>();
    data.put("configurationId", "null");
    data.put("startUrl", "http://blog.ahmetbutun.net");
    Future<Response> asyncRes = target(mockUrl).request(MediaType.APPLICATION_JSON_TYPE).header("userId", MOCK_CRAWLER_VALID_USER_ID).header("token", AUTHENTICATION_HEADER)
            .async().post(Entity.json(data));

    RestResponse response = asyncRes.get().readEntity(RestResponse.class);

    Assert.assertNotNull(response);
    Assert.assertEquals(AppConstants.ERROR_CODE_INVALID_CONFIGURATION_ID_EXCEPTION, response.getStatusCode());
    Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), response.getMessage().getStatus());
}

希望这有帮助。

关于spring - 使用 jersey 2 和 Spring 编写 "clean"集成测试 - REST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38777005/

相关文章:

maven - 为什么 <excludeGroups> 起作用而 <groups> 不起作用?

java - 如何在 Spring Boot 中抛出外部端点抛出的相同异常

security - 断言纯 RESTful 应用程序需要 HTTPS 是安全的是否正确?

java - 自定义默认登录页面 Alfresco

RESTful - 将子资源添加到资源 : POST/subresource or POST/resource/id/subresource?

json - 使用 Jackson 将列表转换为 json

java - 将字段添加到枚举

unit-testing - 我应该对并发性进行单元测试吗?

java - 如何触发@LastModifiedDate

java - Spring单例内存使用优化