我最近加入了一个团队,试图将一个单一的遗留系统转换为Java中的RESTful服务集。 他们决定使用最新的2.x版本的Jersey作为REST容器,这对我来说不是首选,因为我不是JSR- *规范的忠实拥护者。 但是现在我必须承认,JAX-RS 2.x的运行正确:需要几乎零的样板代码,支持功能的自动发现,并且像其他现代框架一样,更喜欢使用约定而不是配置。 由于该规范还很年轻,因此很难找到具有一些可用代码的优秀教程和启动项目。 我在GitHub上创建了jersey2-starter项目,该项目可用作您自己的生产就绪RESTful服务的起点。 在本文中,我想介绍如何实现和集成测试您自己的REST资源验证约束。

自定义约束

用Java编写REST时困扰我的问题之一是用注释乱扔您的类模型。 假设您想构建一个简单的Todo列表REST服务,当使用Jackson,validation和Spring Data时,您可以轻松地将其作为实体类结束:

@Document
public class Todo {private Long id;@NotNullprivate String description;@NotNullprivate Boolean completed;@NotNullprivate DateTime dueDate;@JsonCreatorpublic Todo(@JsonProperty("description") String description, @JsonProperty("dueDate") DateTime dueDate) {this.description = description;this.dueDate = dueDate;this.completed = false;}// getters and setters
}

您的域模型现在几乎到处都被混乱的注释有效地模糊了。 让我们看看如何使用验证约束( @NotNull )。 有人可能会说您可以引入一些具有自己的验证规则的DTO层,但是这与纯REST API设计对我来说是冲突的,后者表示您在应映射到您的域类的资源上进行操作。 另一方面– Todo对象有效是什么意思? 创建Todo ,应提供说明和截止日期,但是更新时会怎样? 您应该能够更改描述,截止日期(推迟)和完成标志(标记为完成)中的任何一个,但是您至少应提供其中之一作为有效的修改。 所以我的想法是引入自定义验证约束,用于创建和修改的约束不同:

@Target({TYPE, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidForCreation.Validator.class)
public @interface ValidForCreation {//...class Validator implements ConstraintValidator<ValidForCreation, Todo> {/...@Overridepublic boolean isValid(Todo todo, ConstraintValidatorContext constraintValidatorContext) {return todo != null&& todo.getId() == null&& todo.getDescription() != null&& todo.getDueDate() != null;}}
}@Target({TYPE, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = ValidForModification.Validator.class)
public @interface ValidForModification {//...class Validator implements ConstraintValidator<ValidForModification, Todo> {/...@Overridepublic boolean isValid(Todo todo, ConstraintValidatorContext constraintValidatorContext) {return todo != null&& todo.getId() == null&& (todo.getDescription() != null || todo.getDueDate() != null || todo.isCompleted() != null);}}
}

现在,您可以将验证注释移至REST端点的定义:

@POST
@Consumes(APPLICATION_JSON)
public Response create(@ValidForCreation Todo todo) {...}@PUT
@Consumes(APPLICATION_JSON)
public Response update(@ValidForModification Todo todo) {...}

现在,您可以从模型中删除那些NotNull

整合测试

集成测试通常有两种方法:

  • 测试是在与应用程序不同的JVM上运行的,而该应用程序已部署在其他集成环境中
  • 测试在设置块中以编程方式部署应用程序。

两者都有其优点和缺点,但是对于足够小的服务,我个人更喜欢第二种方法。 设置起来非常容易,并且您只启动了一个JVM,这使得调试非常容易。 您可以使用Arquillian之类的通用框架在容器环境中启动应用程序,但是我更喜欢简单的解决方案,而只是使用嵌入式Jetty。 为了使测试设置100%等效于生产,我正在创建完整的Jetty的WebAppContext并且必须解决所有运行时相关性,才能使Jersey自动发现正常工作。 这可以通过Arrinklian子项目Shrinkwrap解决的Maven 轻松实现:

WebAppContext webAppContext = new WebAppContext();webAppContext.setResourceBase("src/main/webapp");webAppContext.setContextPath("/");File[] mavenLibs = Maven.resolver().loadPomFromFile("pom.xml").importCompileAndRuntimeDependencies().resolve().withTransitivity().asFile();for (File file: mavenLibs) {webAppContext.getMetaData().addWebInfJar(new FileResource(file.toURI()));}webAppContext.getMetaData().addContainerResource(new FileResource(new File("./target/classes").toURI()));webAppContext.setConfigurations(new Configuration[] {new AnnotationConfiguration(),new WebXmlConfiguration(),new WebInfConfiguration()});server.setHandler(webAppContext);

( 此Stackoverflow线程在这里启发了我很多)

现在是该文章最后一部分的时候了:参数化我们的集成测试。 由于我们要测试验证约束,因此有许多要检查的边缘路径(并使您的代码覆盖率接近100%)。 每个案例编写一个测试可能是一个坏主意。 在实用的JUnit解决方案中,我最相信实用主义者团队的Junit Params 。 它非常简单,并且具有用于创建提供程序的类似于JQuery的帮助程序的概念。 这是我的测试代码(我也在这里使用构建器模式来创建各种Todos):

@Test
@Parameters(method = "provideInvalidTodosForCreation")
public void shouldRejectInvalidTodoWhenCreate(Todo todo) {Response response = createTarget().request().post(Entity.json(todo));assertThat(response.getStatus()).isEqualTo(BAD_REQUEST.getStatusCode());
}private static Object[] provideInvalidTodosForCreation() {return $(new TodoBuilder().withDescription("test").build(),new TodoBuilder().withDueDate(DateTime.now()).build(),new TodoBuilder().withId(123L).build(),new TodoBuilder().build());
}

OK,足够的阅读了,随时克隆项目并开始编写REST服务!

参考: 在我们的JCG合作伙伴 Piotr Jagielski的“ 全栈JVM开发”博客中, 在Jersey 2中集成测试自定义验证约束 。

翻译自: https://www.javacodegeeks.com/2014/03/integration-testing-custom-validation-constraints-in-jersey-2.html

在Jersey 2中进行集成测试自定义验证约束相关推荐

  1. yii2中的rules 自定义验证规则详解

    yii2的一个强大之处之一就是他的Form组件,既方便又安全.有些小伙伴感觉用yii一段时间了,好嘛,除了比tp"难懂"好像啥都没有. 领导安排搞一个注册的功能,这家伙刷刷刷的又是 ...

  2. Java中布尔值的定义_使用简单的布尔值作为自定义验证器

    我正在Angular 4中尝试表单验证,我对实现自定义验证器有点困惑 . 这是我的表格组声明: this.signupForm = fb.group({ 'username': [null, Vali ...

  3. 在ASP.NET MVC中使用Knockout实践07,自定义验证信息的位置与内容

    在前两篇中,体验了Knockout的基本验证和自定义验证.本篇自定义验证信息的显示位置与内容. 自定义验证信息的显示位置 通常,Knockout的验证信息紧跟在input后面,通过validation ...

  4. Laravel 中自定义 验证,例如身份证号验证

    在laravel 5.5之后,您可以创建自己的自定义验证规则对象. 要创建新规则,只需运行Artisan命令: php artisan make:rule Id laravel将把新的rule类放在a ...

  5. vue中的表单手机号和邮箱自定义验证规则

    文章目录 前言 手机号和邮箱的自定义验证 前言 我们在开发过程中使用element UI 或者element-plus 中的表单的时候,会使用到表单验证,比如手机号和邮箱的验证: 手机号和邮箱的自定义 ...

  6. ASP.NET Core 中如何通过 AuthorizeAttribute 做自定义验证?

    咨询区 jltrem: 我想在 ASP.NET Core 中用 authorization 特性实现一个自定义验证,在之前的版本中,我可以用系统提供的 bool AuthorizeCore(HttpC ...

  7. Element UI 表单在el-form-item中使用自定义验证规则

    1:官网示例 <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleFo ...

  8. Excel中7种自定义数据验证设置

    在Excel中,利用数据验证可以对数据的录入添加一定的限制条件.比如我们可以通过数据验证的基本设置使单元格只能录入整数.小数.时间.日期等,也可以创建下拉菜单选项.数据验证的基本功能在前面的文章已进行 ...

  9. 教你三种Model(AR)中自定义验证规则的方法

    2019独角兽企业重金招聘Python工程师标准>>> 各位Yii2兄弟都知道Model的rules里面可以使用自己定义的验证规则,我们今天就把自定义规则做一个总结,进行一次彻底的知 ...

最新文章

  1. GlusterFS的安装及使用
  2. The Illustrated Transformer 翻译
  3. secureCRT的安装及破解
  4. SpringBoot中使用 Druid 数据库连接池, 后台SQL监控无效
  5. SAP License:SAP资产管理模块中的相关业务处理
  6. html前端通过canvas生成验证码
  7. 新手驾车操作指南[200P]
  8. wpf silverlight的Behavior
  9. 模式识别+Matlab 最大似然分类(MLC)【贝叶斯(Bayes)分类法】
  10. 计算机没有显示光盘图标,电脑光驱图标不见了怎么办
  11. python实时语音转写_语音识别 - 实时语音转写 - 《科大讯飞REST_API开发指南》 - 书栈网 · BookStack...
  12. 基于HTML+CSS+JavaScript仿华为手机电子商城
  13. 金盾播放器android安卓,(金盾高级视频加密系统跨平台播放器Android安卓安装步骤.doc...
  14. 混合移动应用中地图导航功能开发与应用
  15. 9月20日科技资讯|余承东硬刚 iPhone11;苹果推送正式版 iOS 13;php-nsq 3.4.3 线上稳定版发布
  16. javascript 中文转拼音代码
  17. Linux、Qt等安装镜像下载--清华大学开源软件镜像站
  18. 再生龙linux多挂载点备份,利用Clonezilla(再生龙)对Linux系统备份与恢复
  19. ESP8266-NodeMCU驱动TFT-SPI彩屏(驱动芯片ILI9341)- 第一个例程【1】
  20. HTML5课程心得学生,HTML5培训心得体会

热门文章

  1. MybatisPlus学习(四)条件构造器Wrapper方法详解
  2. java流与文件——操作文件
  3. java 轻量级文件数据库_Java:如何创建轻量级数据库微服务
  4. jooq_jOOQ星期二:拉斐尔·温特豪德(Rafael Winterhalter)正在与字节好友合作字节码...
  5. java 函数式编程_Java函数式编程:Javaslang入门
  6. javaone_JavaOne和OOW 2015总结
  7. 简述垃圾对象产生_使用零垃圾创建数百万个对象
  8. primefaces_使用Bean验证扩展PrimeFaces CSV
  9. 更好的默认NullPointerException消息是否会传入Java?
  10. MVC 1.0的可能方法