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

我最近加入了一个团队,试图将一个单一的遗留系统转换为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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364901.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql什么实务_MysQL是什么类型的据库?

【单选题】【听力题】Listen to the interview with Ajay, someone from India. Are the following statements true or false? (6.0分)【听力题】Listen to the talk about the changing of the guard ceremony in London. Then fill in the details in the process. (8.0分)…

tomcat7使用dbcp连接池遇到的坑

项目部署在tomcat后每隔一段时间便会报错 Cause: java.sql.SQLException: Could not retrieve transation read-only status server ; SQL []; Could not retrieve transation read-only status server; nested exception is java.sql.SQLException: Could not retrieve transa…

纯CSS实现3D照片墙

HTML部分&#xff1a; <body><div class"photo-wrap"> <!-- 舞台 --><div class"container"> <!-- 容器 --><div class"img">我是中心</div><div class"img img01"><img src&q…

Neo4j Backup:在Mark Needham上存储副本和一致性检查

我上周写的有关 Neo4j在线备份工具的鲜为人知的事情之一是&#xff0c;从概念上讲&#xff0c;它包含两个部分&#xff1a; 将商店文件复制到您选择的位置 验证这些存储文件是否一致。 默认情况下&#xff0c;这两个命令都在您运行“ neo4j-backup”脚本时运行&#xff0c;但…

Guava之RangeMap

在Guava官方API上面可以得知&#xff1a;RangeMap是一种集合类型( collection type)&#xff0c;它将不相交、且不为空的Range&#xff08;key&#xff09;映射给一个值&#xff08;Value&#xff09;。和RangeSet不一样&#xff0c;RangeMap不可以将相邻的区间合并&#xff0c…

sqoop遇到mysql字段为保留字_关于在sqoop 导出数据到mysql数据库的过程对于空字符的处理。...

今天在做sqoop的导入和导出的操作。在导出数据到mysql数据库的时候一直有问题&#xff0c;在导入空字段的时候就出现下面这个错误。WARN hdfs.DFSClient: Caught exceptionjava.lang.InterruptedExceptionat java.lang.Object.wait(Native Method)at java.lang.Thread.join(Thr…

CSS3新增的伪类选择器

伪类选择器的作用&#xff1a;对已有选择器做进一步的限制&#xff0c;对已有选择器能匹配的元素做进一步的过滤。CSS 3提供的伪类选择器主要分为以下三类&#xff1a; 结构性伪类选择器UI元素状态伪类选择器其他伪类选择器 1、结构性伪类选择器 Selector:root&#xff1a;匹…

签名SOAP消息–生成封装的XML签名

数字签名是使数字内容真实可信的一种广泛使用的机制。 通过为某些内容生成数字签名&#xff0c;我们可以让另一方能够验证该内容。 通过此验证&#xff0c;它可以保证在我们签名后不会更改。 通过这个示例&#xff0c;我将分享如何为SOAP信封生成签名。 但是&#xff0c;这当然…

2019 The 19th Zhejiang University Programming Contest

感想&#xff1a; 今天三个人的状态比昨天计院校赛的状态要好很多&#xff0c;然而三个人都慢热体质导致签到题wa了很多发。最后虽然跟大家题数一样(6题)&#xff0c;然而输在罚时。 只能说&#xff0c;水题还是刷得少&#xff0c;看到签到都没灵感实在不应该。 题目链接&#…

openvas安装和基本使用

OpenVAS是开放式漏洞评估系统&#xff0c;也可以说它是一个包含着相关工具的网络扫描器。OpenVAS是开放式漏洞评估系统&#xff0c;也可以说它是一个包含着相关工具的网络扫描器。其核心部件是一个服务器&#xff0c;包括一套网络漏洞测试程序&#xff0c;可以检测远程系统和应…

修改mysql编码方式centos_CentOS下修改mysql数据库编码为UTF-8(附mysql开启远程链接和开放3306端口)...

楼主在配置好linux云服务器的jdk,tomcat,mysql后&#xff0c;当要开始部署项目是&#xff0c;忽然意识到一个很严重的问题&#xff0c;那就是数据库的编码问题&#xff0c;自安装完成后并未修改数据库的额编码。。。。下面就来讲说linux下修改mysql的编码问题吧。。有一个问题网…

Java 8 Lambda表达式的函数式编程– Monads

什么是monad &#xff1f;&#xff1a; monad是一种设计模式概念&#xff0c;用于大多数功能编程语言&#xff08;如Lisp&#xff09;或现代世界的Clojure或Scala中。 &#xff08;实际上&#xff0c;我会从scala复制一些内容。&#xff09;现在&#xff0c;为什么它在Java中变…

srtvlet filter

Filter&#xff0c;过滤器&#xff0c;顾名思义&#xff0c;即是对数据等的过滤&#xff0c;预处理过程。为什么要引入过滤器呢&#xff1f;在平常访问网站的时候&#xff0c;有时候发一些敏感的信息&#xff0c;发出后显示时 就会将敏感信息用*等字符替代&#xff0c;这就是用…

mysql怎么合并行_mysql怎么合并行

mysql合并行的方法&#xff1a;使用函数【GROUP_CONCAT()】&#xff0c;代码为【SELECT am.activeId,GROUP_CONCAT(m.modelName SEPARATOR ‘,’) modelName】。【相关学习推荐&#xff1a;mysql学习】mysql合并行的方法&#xff1a;一个字段可能对应多条数据&#xff0c;用mys…

ubuntu 14 编译ARM g2o-20160424

1. 安装eigen sudo apt-get install libeigen3-dev sudo apt-get install libsuitesparse-dev sudo apt-get install libqglviewer-dev 对于ARM版本&#xff0c;可以下载http://eigen.tuxfamily.org&#xff0c;之后放置在toolchain可以找到的三方库位置处&#xff0c;我使用的…

将旧项目从Ant迁移到Maven的4个简单步骤

一段时间以来&#xff0c;我们一直在考虑将构建从蚂蚁移植到Maven。 它发生在上个月&#xff0c;实际上比我们预期的要简单。 根据我的经验&#xff0c;这里简要介绍了我们遵循的步骤。 我们的应用程序是一个具有多个框架和技术的企业Web应用程序构建&#xff0c;并作为单个WAR…

浅谈servlet与jsp的关系

servlet是用java语言编写的&#xff0c;是一个java类。主要功能是用来接受、处理客户端的请求&#xff0c;并把处理结果返回到客户端显示。Jsp是servlet发展后期的产物。在没有jsp之前&#xff0c;servlet利用输出流动态生成整个HTML页面&#xff0c;输出内容包括每一个HTML标签…

折腾Java设计模式之建造者模式

博文原址&#xff1a;折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, allowing the same construction process to create various representations. 将复杂对象的构造与其表现分离&#xff0c;允许相同的构…

python小甲鱼练习题答案_小甲鱼Python第 013讲元组:戴上了枷锁的列表 | 课后测试题及参考答案...

测试题&#xff1a;0. 请用一句话描述什么是列表&#xff1f;再用一句话描述什么是元组&#xff1f;列表&#xff1a;一个大仓库&#xff0c;可以随时往里面添加和删除任何东西。元祖&#xff1a;封闭的列表&#xff0c;一旦定义&#xff0c;就不可改变(不能添加、删除或修改)1…

获得的经验:ActiveMQ,Apache Camel和连接池

每隔一段时间&#xff0c;我会遇到一个与ActiveMQ的连接和池相关的有趣问题&#xff0c;而今天&#xff0c;我想讨论一些并不总是很清楚的问题&#xff0c;并且在使用ActiveMQ和Camel JMS时可能会导致您大量饮酒。 并不是说您无论如何都不会在使用ActiveMQ和Camel时大量喝酒………