在我们所有的项目中,我们使用的数据类根据定义包含数据(字段),但不包含(业务)逻辑。
根据最佳编码实践,数据类最好应该是不可变的,因为不可变性意味着线程安全。 这里的主要参考是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