使用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批注轻松地定义一个不可变的类,如下所示:

@Value
    public 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 {

      @Test
      public void testClassIsImmutable() {
        assertImmutable(ImmutableBean.class);
      }
    }

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

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

org.mutabilitydetector.unittesting.MutabilityAssertionError: 
Expected: it.gualtierotesta.testsolutions.general.beans.ImmutableBean to be IMMUTABLE
 but: 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值