使用Mutability Detector对Java数据类的不变性进行单元测试

在我们所有的项目中,我们使用的数据类根据定义包含数据(字段),但不包含(业务)逻辑。

根据最佳编码实践,数据类最好应该是不可变的,因为不可变性意味着线程安全。 这里的主要参考是Joshua Bloch的Effective Java书籍; Yegor Bugayenko的帖子也很有趣。

不可变类具有几个有趣的属性:

  • 它不能是子类的(即它应该是最终的,或者应该具有静态工厂方法和私有构造函数)
  • 所有字段均应为私有字段(以防止直接访问)
  • 所有字段应写入一次(在实例创建时)(即,它们应该是最终值且没有设置方法)
  • 所有可变类型(例如java.util.Date)字段都应受到保护,以防止客户端通过引用进行写访问

不变类的示例如下:

public final class ImmutableBean {private final String aStr;private final int anInt;public ImmutableBean(String aStr, int anInt) {this.aStr = aStr;this.anInt = anInt;}public String getAStr() {return aStr;}public int getAnInt() {return anInt;}}

注意:在Java中很常见,有很多样板代码隐藏了不变性定义。

像Project Lombok这样的库使我们的生活更轻松,因为我们可以使用@Value批注轻松地定义一个不可变的类,如下所示:

@Valuepublic class LombokImmutableBean {String aStr;int anInt;}

更具可读性。

我们(单元)应该测试一个类以检查其不变性吗?

在理想世界中,答案是否定的。

借助我们首选的IDE自动代码生成功能或Lombok之类的库,为类添加不变性并不难。

但是在现实世界中,当我们创建类或稍后(或可能是团队的初级成员)修改类时,可能会发生人为错误。 如果不使用final来添加新字段并且使用IDE代码生成器生成了setter会怎样? 该类不再是不变的。

重要的是要确保该类在整个项目生命周期中都是并且保持不变。

借助Mutability Detector,我们可以轻松创建一个测试来检查类的不变性状态。

像往常一样,可以在Maven Central上找到Maven / Gradle依赖项。

为了测试我们的ImmutableBean,我们可以创建以下jUnit测试类:

import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable;public class ImmutableBeanTest {@Testpublic void testClassIsImmutable() {assertImmutable(ImmutableBean.class);}}

如果类不是不可变的,则测试将失败。

例如,如果一个字段不是final且具有setter方法,则测试将失败,并且错误消息的描述性非常强:

org.mutabilitydetector.unittesting.MutabilityAssertionError: 
Expected: it.gualtierotesta.testsolutions.general.beans.ImmutableBean to be IMMUTABLEbut: it.gualtierotesta.testsolutions.general.beans.ImmutableBean is actually NOT_IMMUTABLE
Reasons:Field is not final, if shared across threads the Java Memory Model will not guarantee it is initialised before it is read. [Field: aStr, Class: it.gualtierotesta.testsolutions.general.beans.ImmutableBean]Field [aStr] can be reassigned within method [setaStr] [Field: aStr, Class: it.gualtierotesta.testsolutions.general.beans.ImmutableBean]

完整的项目可以在我在GitHub上的Test Solutions画廊项目中找到。 参见模块常规

我建议的方法是使用Lombok,而不进行任何不变性测试。 如果不能使用Lombok(例如在旧项目中),请使用“可变性检测器”声明该类确实是不可变的。

翻译自: https://www.javacodegeeks.com/2017/01/unit-testing-java-data-classes-immutability-mutability-detector.html

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

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

相关文章

三种单例模式的C++实现

简介 因为在设计或开发中,肯定会有这么一种情况,一个类只能有一个对象被创建,如果有多个对象的话,可能会导致状态的混乱和不一致。这种情况下,单例模式是最恰当的解决办法。它有很多种实现方式,各自的特性不…

centos安装Redis

vRedis的安装 ♛ 1.0 下载Rediswget http://download.redis.io/releases/redis-5.0.2.tar.gz ♛ 1.1 解压tar -zxvf redis-5.0.2.tar.gz ♛ 1.2 安装gcc依赖Redis是C实现的,需要gcc来进行编译,先安装gcc。 yum install gcc ♛ 1.3 打开Redis目录cd redis…

maven插件编写_编写Maven插件的提示

maven插件编写最近,我花了很多时间为Maven编写插件或在其中工作。 它们简单,有趣且有趣。 我以为我会分享一些技巧,使编写它们时的生活更轻松。 提示1:将任务与Mojo分开 最初,您将把mojo的所有代码放入mojo的类&…

e3是合法浮点数吗_下列哪些是不合法的浮点数的选项是 123 2e4.2 .e5 -e3 .234 1e3

共回答了16个问题采纳率:93.8%浮点数是属于有理数中某特定子集的数的数字表示,在计算机中用以近似表示任意某个实数.具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表示方法类似于基数为10的科学记数法.由此可以看出…

VC的Win32控制台程序中使用MFC库文件

如果想要在VC中的Win32控制台程序中使用CString类&#xff0c;应注意下列情况&#xff1a; 1.必须包含头文件#include <afx.h> 2.Project ----settings... ----General---- Microsoft Foundation Classes: Use MFC in a Shared DLL

java能否调用com_java调用com

一、C#写com组件开发环境 vs20051、新建工程:ClassLibrary1 //根据自己需要取工程名2、右键点击工程->应用程序->程序集信息->使程序集com可见&#xff0c;打上勾右键点击工程->生成->为com Interop注册 打上勾3、设置强签名打开Visual Studio Command Pr…

JUnit规则–引发异常时执行附加验证

在本文中&#xff0c;我将快速向您展示如果您需要解决以下挑战&#xff0c;那么JUnit规则有多方便 方法捕获异常并必须执行一些额外的任务&#xff0c;然后再抛出或引发包装异常。 调用额外任务和引发的异常应通过单元测试进行验证。 这意味着您有一些这样的代码 public cla…

十分钟搞清字符集和字符编码

什么是字符集 什么是字符编码 UTF-8和Unicode的关系 UTF-8编码简介 为什么会出现乱码 如何识别乱码的本来想要表达的文字 常见问题处理之Emoji 本文将简述字符集&#xff0c;字符编码的概念。以及在遭遇乱码时的一些常用诊断技巧 背景&#xff1a;字符集和编码无疑是IT菜鸟甚至…

前端Ajax/JS/HTML+后端SpringMVC(二)

1. jQuery AJAX 1.1. jQuery框架中的ajax()函数 在应用了jQuery框架后&#xff0c;调用ajax()函数即可发出AJAX请求&#xff0c;并获取响应结果&#xff0c;该函数的参数必须是JSON对象&#xff0c;通常&#xff0c;在JSON对象中封装的属性有&#xff1a; url&#xff1a;处理请…

java lambda函数_番石榴函数和Java 8 Lambdas

java lambda函数我最近阅读了Brian Goetz的《 Lambda的状况》 &#xff0c;在阅读了该文章之后&#xff0c;我想尝试使用Java 8 Lambda表达式。 Brian在他的文章中继续描述了将一种方法称为“功能”接口的接口。 功能接口几乎总是用作匿名类&#xff0c;其中ActionListener是规…

c++组合 聚合 关联

组合和聚合区别(不能脱离整体 能脱离整体) 组合&#xff1a;&#xff08;表示两个对象之间是整体和部分的强关系&#xff0c;部分的生命周期不能超越整体。如人和脑袋&#xff09; 比如A类中包含B类的一个引用b&#xff0c;当A类的一个对象消亡时&#xff0c;b这个引用所指向的…

python内建时间模块 time和datetime

时间模块 UTC&#xff08;Coordinated Universal Time&#xff0c;世界协调时&#xff09;亦即格林威治天文时间&#xff0c;世界标准时间。在中国为UTC8。DST&#xff08;Daylight Saving Time&#xff09;即夏令时。 在Python中,通常有这几种方式来表示时间&#xff1a;1&…

java tomcat自动安装教程_Tomcat:基础安装和使用教程

背景此文记录了 Tomcat 的基本使用方法&#xff0c;主要为了强化记忆。安装步骤第一步&#xff1a;下载和安装 Java安装并设置JAVA_HOME环境变量&#xff1a;第二步&#xff1a;下载和解压 Tomcat第三步&#xff1a;修改端口号.NET 我使用的是 80xx&#xff0c;Php 我使用的是 …

C++ 智能指针五

/* 代码分析:这是标准库的源码&#xff0c;我们看到在enable_shared_from_this内部保存了一个weak_ptr。shared_from_this函数就是通过这个weak_ptr得到了。 但是另外一点&#xff0c;我们可以看到在enable_shared_from_this的构造函数中并没有对这个weak_ptr进行初始化。 这就…

多线程之间共享的资源有哪些

搜集了一下资料&#xff0c;网上的说法众说纷纭&#xff1b;曾经以为进程、线程的问题搞得很清楚&#xff0c;现在感觉似乎有些复杂&#xff1a; 课本的说法&#xff1a;进程是资源分配的基本单位&#xff1b;线程是系统调度的基本单位。平时我们写的程序都是作为线程运行的&am…

mybatis一级缓存导致sql查询出现问题

如下代码&#xff1a; PubPsndoc pubdoc pubPsndocDAOService.selectByPrimaryKey(in.id);pubdoc.setPkCorp(newpkcorp);pubdoc.setPkDept(newpkdept);pubPsndocDAOService.update(pubdoc); PubPsndoc personPubdoc pubPsndocDAOService.selectByPrimaryKey(in.id); 在上述代…

使用JavaParser从源文件中提取JavaDoc文档

很多人正在使用JavaParser实现最不同的目标。 其中之一是提取文档。 在这篇简短的文章中&#xff0c;我们将看到如何打印与类或接口关联的所有JavaDoc注释。 可以在GitHub上找到代码&#xff1a; https : //github.com/ftomassetti/javadoc-extractor 获取类的所有Javadoc注释…

三个打印函数printf()/sprintf()/snprintf()区别

先贴上其函数原型 printf( const char *format, ...) 格式化输出字符串&#xff0c;默认输出到终端-----stdout sprintf(char *dest, const char *format,...) 格式化输出字符串到指定的缓冲区 snprintf(char *dest, size_t size,const char *format,...) 按指定的S…

JAVA客户端数据传输_java模拟TCP通信实现客户端上传文件到服务器端

java模拟TCP通信实现客户端上传文件到服务器端&#xff0c;供大家参考&#xff0c;具体内容如下客户端package com.zr;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import jav…

js闭包简单演示

function f1() { var age 20; var height 170; function f2() { console.log("aaa:"(age) "--bbb:"height); } return f2; } var ff f1(); var fa f1(); fa(); fa(); ff(); ff(); 这里有两个闭包&#xff0c;fa和ff分别保存的信息独立&#xff0c;age…