赞扬别人团建评论_赞扬精心设计:基于属性的测试如何帮助我成为更好的开发人员...

赞扬别人团建评论

开发人员的测试工具箱就是其中之一,很少保持不变。 可以肯定的是,一些测试实践已被证明比其他测试更有价值,但是,我们仍在不断寻找更好,更快和更具表现力的方法来测试我们的代码。 基于属性的测试 是 Java社区中鲜为人知的 ,这是Haskell员工精心制作的另一种瑰宝,并在QuickCheck论文中进行了介绍 。

Scala社区(诞生了ScalaCheck库的Scala社区)和许多其他组织很快意识到了这种测试技术的强大功能,但是Java生态系统在相当长的一段时间内一直缺乏采用基于属性的测试的兴趣。 幸运的是,自从jqwik出现以来,情况就在慢慢变化, 以求更好。

对于许多人来说,很难掌握什么是基于属性的测试以及如何利用它。 杰西卡·克尔 ( Jessica Kerr)的精彩演讲《基于属性的测试,更好的代码》 ,以及有关基于属性的测试的简介,基于 属性的测试模式系列的文章,是吸引您的绝佳来源,但是在今天的帖子中,我们将尝试发现典型的Java开发人员使用jqwik进行的基于属性的测试的实践方面。

首先, 基于属性的测试名称实际上意味着什么? 每个Java开发人员首先想到的是它旨在测试所有的getter和setters(您好100%覆盖率)吗? 并非如此,尽管对于某些数据结构而言可能很有用。 相反,我们应该确定组件,数据结构甚至单个功能的高级特性 ,并通过提出假设有效地对其进行检验。

我们的第一个示例属于“那里又回来”类别:将序列化和反序列化为JSON表示形式。 被测试的类是User POJO ,虽然很简单,但请注意它具有OffsetDateTime类型的一个时间属性。

 public class User { private String username; @JsonFormat (pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS[SSS]]XXX" , shape = Shape.STRING) private OffsetDateTime created;     // ...  } 

令人惊讶的是,由于所有人都在尝试使用自己的表示形式,因此最近几天使用日期/时间属性进行操作会引起问题。 如您所见,我们的合同使用的是ISO-8601互换格式,带有可选的毫秒部分。 我们要确保的是,可以将任何有效的User实例序列化为JSON ,然后反序列化为Java对象,而不会失去任何日期/时间精度。 作为练习,让我们尝试首先用伪代码来表达它:

 For any user Serialize user instance to JSON Deserialize user instance back from JSON Two user instances must be identical 

看起来很简单,但令人惊讶的部分出在这里:让我们看一下如何使用jqwik库将此伪代码投影到真实的测试用例中。 它尽可能地接近我们的伪代码。

 @Property  void @ForAll serdes( @ForAll ( "users" ) User user) throws JsonProcessingException { final String json = serdes.serialize(user); assertThat(serdes.deserialize(json)) .satisfies(other -> { assertThat(user.getUsername()).isEqualTo(other.getUsername()); assertThat(user.getCreated().isEqual(other.getCreated())).isTrue(); });         Statistics.collect(user.getCreated().getOffset());  } 

测试用例读起来很简单,通常是自然的,但是显然, jqwik的@Property@ForAll批注后面隐藏着一些背景。 让我们从@ForAll开始,并清除所有这些User实例的来源。 您可能猜到了,这些实例必须生成,最好以随机方式生成。

对于大多数内置数据类型, jqwik具有一组丰富的数据提供程序( Arbitraries ),但是由于我们要处理特定于应用程序的类,因此我们必须提供自己的生成策略。 它应该能够发出具有广泛的用户名以及不同时区和偏移量集合的日期/时刻的User类实例。 首先让我们先略过提供者的实现,然后再详细讨论。

 @Provide  Arbitrary<User> users() { final Arbitrary<String> usernames = Arbitraries.strings().alpha().ofMaxLength( 64 );  final Arbitrary<OffsetDateTime> dates = Arbitraries .of(List.copyOf(ZoneId.getAvailableZoneIds())) .flatMap(zone -> Arbitraries .longs() .between(1266258398000L, 1897410427000L) // ~ +/- 10 years .unique() .map(epochMilli -> Instant.ofEpochMilli(epochMilli)) .map(instant -> OffsetDateTime.from(instant.atZone(ZoneId.of(zone))))); return Combinators .combine(usernames, dates) .as((username, created) -> new User(username).created(created));  } 

用户名的来源很简单:只是随机字符串。 日期的来源基本上可以是2010年到2030年之间的任何日期/时间,而时区部分(因此是偏移量)是从所有可用的基于区域的区域标识符中随机选择的。 例如,下面是jqwik提出的一些示例。

 { "username" : "zrAazzaDZ" , "created" : "2020-05-06T01:36:07.496496+03:00" }  { "username" : "AZztZaZZWAaNaqagPLzZiz" , "created" : "2023-03-20T00:48:22.737737+08:00" }  { "username" : "aazGZZzaoAAEAGZUIzaaDEm" , "created" : "2019-03-12T08:22:12.658658+04:00" }  { "username" : "Ezw" , "created" : "2011-10-28T08:07:33.542542Z" }  { "username" : "AFaAzaOLAZOjsZqlaZZixZaZzyZzxrda" , "created" : "2022-07-09T14:04:20.849849+02:00" }  { "username" : "aaYeZzkhAzAazJ" , "created" : "2016-07-22T22:20:25.162162+06:00" }  { "username" : "BzkoNGzBcaWcrDaaazzCZAaaPd" , "created" : "2020-08-12T22:23:56.902902+08:45" }  { "username" : "MazNzaTZZAEhXoz" , "created" : "2027-09-26T17:12:34.872872+11:00" }  { "username" : "zqZzZYamO" , "created" : "2023-01-10T03:16:41.879879-03:00" }  { "username" : "GaaUazzldqGJZsqksRZuaNAqzANLAAlj" , "created" : "2015-03-19T04:16:24.098098Z" }  ... 

默认情况下, jqwik将针对1000套不同的参数值(随机用户实例)运行测试。 非常有用的“ 统计”容器允许收集您好奇的任何分布见解。 以防万一,为什么不按区域偏移量收集分布呢?

 ... - 04 : 00 ( 94 ) : 9.40 % - 03 : 00 ( 76 ) : 7.60 % + 02 : 00 ( 75 ) : 7.50 % - 05 : 00 ( 74 ) : 7.40 % + 01 : 00 ( 72 ) : 7.20 % + 03 : 00 ( 69 ) : 6.90 % Z     ( 62 ) : 6.20 % - 06 : 00 ( 54 ) : 5.40 % + 11 : 00 ( 42 ) : 4.20 % - 07 : 00 ( 39 ) : 3.90 % + 08 : 00 ( 37 ) : 3.70 % + 07 : 00 ( 34 ) : 3.40 % + 10 : 00 ( 34 ) : 3.40 % + 06 : 00 ( 26 ) : 2.60 % + 12 : 00 ( 23 ) : 2.30 % + 05 : 00 ( 23 ) : 2.30 % - 08 : 00 ( 20 ) : 2.00 % ... 

让我们考虑另一个例子。 想象一下,我们决定基于用户名属性重新实现User类的相等性(在Java中,这意味着重写equalshashCode )。 这样,对于任何一对User类实例,以下不变量必须为true:

  • 如果两个User实例具有相同的用户名 ,则它们相等,并且必须具有相同的哈希码
  • 如果两个User实例具有不同的username ,则它们不相等(但哈希码不一定相同)

它非常适合基于属性的测试,并且jqwik尤其使这种测试的编写和维护变得微不足道。

 @Provide  Arbitrary&ltString> usernames() { return Arbitraries.strings().alpha().ofMaxLength( 64 );  }  @Property  void equals( @ForAll ( "usernames" ) String username, @ForAll ( "usernames" ) String other) { Assume.that(!username.equals(other));         assertThat( new User(username)) .isEqualTo( new User(username)) .isNotEqualTo( new User(other)) .extracting(User::hashCode) .isEqualTo( new User(username).hashCode());  } 

由于我们引入了用户名的两个来源,因此通过假设表达的假设允许对生成的参数施加额外的约束,这可能会发生,因为它们在同一运行中都发出相同的用户名,因此测试将失败。

您到目前为止可能遇到的问题是:重点是什么? 当然可以在不进行基于属性的测试和使用jqwik的情况下测试序列化/反序列化或equals / hashCode ,那么为什么还要麻烦呢? 足够公平,但是这个问题的答案基本上深深在于我们如何进行软件系统的设计。

总体而言, 基于属性的测试在很大程度上受函数式编程的影响,这并不是Java的第一件事(至少现在还不是),这要轻描淡写地说。 随机生成测试数据本身并不是一个新颖的主意,但是至少在我看来, 基于属性的测试鼓励您去做的是,以更抽象的角度思考,而不是专注于单个操作(等于,比较,加法)。 ,排序,序列化...),但是它们要遵循什么样的属性,特征,定律和/或不变式。 当然,这感觉就像是一种外来技术,如果您愿意的话,可以改变范式,鼓励您花更多的时间设计正确的东西。 这并不意味着从现在开始您的所有测试都必须基于属性,但是我相信它当然应该在我们的测试工具箱的前排位置。

请在Github上找到完整的项目资源。

翻译自: https://www.javacodegeeks.com/2020/02/in-praise-of-the-thoughful-design-how-property-based-testing-helps-me-to-be-a-better-developer.html

赞扬别人团建评论

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

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

相关文章

linux c read函数返回值,Linuxc - GNU Readline 库及编程简介

GNU Readline 库及编程简介简介用过 Bash 命令行的一定知道&#xff0c;Bash 有几个特性&#xff1a;TAB 键可以用来命令补全↑ 或 ↓ 键可以用来快速输入历史命令还有一些交互式行编辑快捷键&#xff1a;C-A / C-E 将光标移到行首/行尾C-B / C-F 将光标向左/向右移动一个位置C…

java泛型——桥方法

【0】README 0.1&#xff09;以下内容转自&#xff1a; http://www.cnblogs.com/ggjucheng/p/3352519.html 【1】泛型约束和局限性—— 类型擦除所带来的麻烦 1.1&#xff09;继承泛型类型的多态麻烦。&#xff08;—— 子类没有覆盖住父类的方法 &#xff09; 看看下面这个…

Hibernate框架之入门配置

一、Hibernate导入相关的包参考&#xff1a;http://blog.csdn.net/tunni/article/details/54982160这些包包括相应数据库驱动、hibernate.zip下lib目录下的jar包&#xff0c;其中必须包是required目录下的.jar二、在项目classpath&#xff08;类路径&#xff0c;即src目录下&am…

annotations_Spring Annotations我从来没有机会使用第2部分:@ConfigurationProperties

annotations几天前&#xff0c;我在检查其他内容时不小心偶然发现了Spring Boot项目中的Spring注释。 我们都知道如何将带有“ Value”的属性值绑定到类&#xff0c;并且我们都知道如果要绑定多个属性&#xff0c;这可能会很麻烦。 Spring Boot可以为您提供帮助。 您可以使用“…

linux下检测硬盘,【转载】linux下硬盘监控诊断工具SmartTools

对于windwos下raid卡具备告警功能&#xff0c;当硬盘故障、raid卡告警时&#xff0c;可以发邮件给管理员。IBM、HP、Dell都支持。但在linux下&#xff0c;就没有找到相关的好工具了&#xff0c;今天到陈沙克的博客上到一篇关于linux下硬盘监控诊断工具SmartTools&#xff0c;感…

hibernate框架之主键生成

一、 hibernate 框架中主键的生成策略 (1)native: 表示由设置的方言决定采用什么数据库生成主键方式&#xff0c;根据底层数据库能力选择identity、sequence中的一个。 例如&#xff1a;在MySQL中会采用自增长的方式&#xff0c;主键字段必须都是整形类型&#xff1b;在Oracle数…

java泛型通配符

【0】README 0.1&#xff09;以下内容转自&#xff1a; http://blog.csdn.net/baple/article/details/25056169 0.2&#xff09; T 有类型 &#xff1f; 未知类型 一、通配符的上界&#xff08;extends关键字&#xff09; 既然知道List并不是List的子类型&#xff0c;那就需…

jdk 1.8 内存可见性_JDK 14中的常规,安全和确定性外部内存访问

jdk 1.8 内存可见性在“ JDK 14 Rampdown&#xff1a;Build 27 ”一文中&#xff0c;我总结了JDK 14 Early Access Build &#xff03;27中新增的许多针对JDK 14的功能。 已经存在另一种JDK 14 Early Access Build&#xff0c;并且此[ Build 28&#xff08;2019/12/18&#xff…

linux开启防火墙ping,如何在防火墙中放开ping

如何在防火墙中放开ping操作时需要注意的几项:1,注意iptables各版本间的区别我们的server os最旧的版本是redhat 7.3 kernel是2.4.20-18.7最新的server os最新的版本是centos 5, kernel是2.6.18-8差距很大iptables以模块形式运行在内核的空间,用lsmod可以看到所以它与内核的版本…

Hibernate: You have an error in your SQL syntax; check the manual that corresponds to your MySQL

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ...Hibernate 出现这样的错误是因为表中的字段名使用了sql的保留字&#xff0c;不要使用保留字 一、mysql的保留字主要有&#xff1…

java.io 包

java.io 通过数据流、序列化和文件系统提供系统输入和输出。 请参见&#xff1a; 接口摘要CloseableCloseable 是可以关闭的数据源或目标。DataInputDataInput 接口用于从二进制流中读取字节&#xff0c;并根据所有 Java 基本类型数据进行重构。DataOutputDataOutput 接口用…

linux系统怎么安装pr,Linux安装后的配置

系统:CentOS-6.31.NVIDIA驱动的安装与配置Linux本身的显卡驱动是能够满足平常应用的&#xff0c;但是有时候我们为了获得3D效果&#xff0c;或者更流畅的视频体验&#xff0c;我们会安装新的显卡驱动。这时候就需要安装闭源驱动了&#xff0c;个人认为闭源的驱动更为好一些&…

java第三阶段源代码_有效Java第三版的源代码已更新为使用较新的功能

java第三阶段源代码那些已经阅读了有效Java 第三版的人可能知道与该书相关的源代码可以在GitHub上获得 。 jbloch / effective-java-3e-source-code项目拥有1700多个星星&#xff0c;截至撰写本文时&#xff0c;它已被分叉了近800次。 在有效Java的第三版中&#xff0c; Java的…

《线性代数及其应用》

【0】README 0.1&#xff09;以下内容转自&#xff1a; http://blog.csdn.net/ljbkiss/article/details/7194719 【1】正文干货 1.1&#xff09; 断断续续的终于把 《线性代数及其应用&#xff08;Linear Algebra and Its Application&#xff09; David C.Lay》 这本书看完了…

micrometer_具有InlfuxDB的Spring Boot和Micrometer第1部分:基础项目

micrometer对于那些关注此博客的人来说&#xff0c;难怪我会经常使用InfluxDB。 我喜欢这样一个事实&#xff0c;它是一个真正的单一用途的数据库&#xff08;时间序列&#xff09;&#xff0c;具有许多功能&#xff0c;并且还带有企业支持。 Spring也是我选择的工具之一。 因…

如何在win7(xp)home version下安装 rose 32 bit

【0】README 0.1&#xff09; 以下部分内容转自 http://blog.csdn.net/encienqi/article/details/5578725 【1】 干货开始 如果是家庭版(win7 or WindowsXPHomeEdition)请先按以下步骤修改部分文件后再安装&#xff1a; 1.1&#xff09;安装Microsoft Orca工具 step1&#x…

接口 Closeable

java.io 接口 Closeable public interface Closeable Closeable 是可以关闭的数据源或目标。调用 close 方法可释放对象保存的资源&#xff08;如打开文件&#xff09;。 从以下版本开始&#xff1a;1.5方法摘要 void close() 关闭此流并释放与此流关联的所有系统资源。 方法详…

Linux下python包放在哪,在alpinlinux中使用apk安装的Python包

我想用apk在Alpine Linux中安装一些Python包。我用numpy作为下面的例子。文档文件FROM python:3-alpineRUN apk add --update py3-numpy我建立我的码头形象$ docker build -t python-numpy .Sending build context to Docker daemon 2.048kBStep 1/2 : FROM python:3-alpine---…

spring 消息传递机制_Spring再次涵盖了您:继续进行消费者驱动的消息传递合同测试...

spring 消息传递机制在上一篇文章中&#xff0c;我们已经开始讨论基于消息的通信中的消费者驱动的合同测试 。 在今天的帖子中&#xff0c;我们将在测试工具箱中包含另一个工具&#xff0c;但是在此之前&#xff0c;让我对显微镜下的系统进行快速回顾。 它有两项服务&#xff0…

接口 DataInput

java.io接口 DataInput 所有已知子接口&#xff1a;ImageInputStream, ImageOutputStream, ObjectInput所有已知实现类&#xff1a;DataInputStream, FileCacheImageInputStream, FileCacheImageOutputStream, FileImageInputStream, FileImageOutputStream, ImageInputStreamI…