如何编写一个测试友好的不可变值类? [英] How to write a test-friendly immutable value class?

查看:169
本文介绍了如何编写一个测试友好的不可变值类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将不可变数据模型类标记为 final ,以确保更改其值的唯一方法是创建新实例。 (不幸的是,这些字段不能是最终字段,因为它们需要由Hibernate填充。)

I marked an immutable data model class as final to make sure the only way to change its values is to create a new instance. (Unfortunately, the fields cannot be final because they needs to be populated by Hibernate.)

这很有效,直到我想检查另一个类在调用时抛出正确的异常模型的无效实例。模型的构造函数验证参数,因此必须使用反射来设置字段。这非常笨拙,因为模型有很多字段,字段名称必须硬编码。

This worked well until I wanted to check another class throws the correct exception when called with an invalid instance of the model. The constructor of the model validates the arguments so reflection must be used to set the fields. This is extremely clumsy since the model have quite a few fields and the field names have to be hard-coded.

我不能模仿模型,因为它是最后。 (在保持类不可变的情况下是否应该使用接口来启用模拟也是有争议的。通过使用接口,无法以编程方式强制命令方法必须在实例的整个生命周期内返回相同的值。)

I can't mock the model either due to it being final. (Is it also debatable whether an interface should be used to enable mocking while keeping the class immutable. By having an interface, there's no way to programmatically mandate the methods must return the same value throughout the life of the instance.)

在这种情况下,人们通常做什么?有没有标准的方法呢?

What do people usually do in this case? Is there any standard approach to this?

推荐答案

一般来说,你不应该想模拟数据对象。数据对象应该没有逻辑,也没有外部依赖关系,因此模拟对象并没有多大用处。相反,可以很容易地创建可以根据需要填充方法的假实例。

Generally speaking, you shouldn't want to mock data objects. Data objects should have no logic and no external dependencies, so there's not really much use to mocking the objects. Instead make it very easy to create fake instances that you can populate in methods as you'd like.

此外,还有一些其他原因可能需要避免处理一个Hibernate持久化对象为不可变的:

Furthermore, there are a few other reasons you might want to avoid treating a Hibernate-persisted object as immutable:


  • Hibernate提供的对象本质上是不是线程安全的因此失去了不可变值对象的线程安全优势通常提供。

  • 您可能会发现您的对象实际上是代理,可能会削弱 final 语义。

  • Hibernate控制的对象操作完全不同他们的会话是否仍然是开放的(附加vs分离)使他们成为不可变对象的一个​​非常糟糕的选择。如果你的不可变对象依赖于会话生命周期,它就不是真正不可变的。

  • 听起来有些对象在应用层可能有效或无效,超出了数据库层验证。这使得封装验证问题变得有点困难。

  • 您需要拥有一个公共的无参数构造函数,这与不可变值对象的典型实例控制类型是对立的。

  • 因为对象本质上是可变的,所以覆盖equals和hashCode 。

  • Hibernate-provided objects are inherently not thread-safe and therefore lose the thread-safety advantages that immutable value objects typically provide.
  • You may find your objects are actually proxies, possibly undercutting the final semantics.
  • Hibernate-controlled objects operate completely differently whether their session is still open (attached vs detached) making them a very poor choice for an immutable object. If your immutable object depends on session lifetime, it's not really immutable.
  • It sounds like some objects may be valid or invalid at the application layer, beyond database-layer validation. That makes it a little harder to encapsulate your validation concerns.
  • You are required to have a public no-arg constructor, which is antithetical to the kind of instance control typical of immutable value objects.
  • Because the objects are inherently mutable, it is more complicated to override equals and hashCode.

我的建议?如果你需要比Hibernate DAO更多的不变性和数据验证保证,那么用最终字段(或私有构造函数和静态工厂方法)创建一个真正的最终不可变类,然后创建一个构造函数(或静态工厂方法)复制来自Hibernate DAO的值。

My advice? If you need more immutability and data validation guarantees than a Hibernate DAO can grant you, then create a real final immutable class with final fields (or a private constructor and static factory method), and then make a constructor (or static factory method) that copies in values from your Hibernate DAO.

如果你决定使用这个选项,你就会遇到 2的开销大致并行改变的数据对象,但你也可以分离关注点(如果Hibernate对象应该分散)以及真正不可变的,等于和哈希码覆盖,会话不可知的保证,保证 - 您可以轻松为测试创建的有效对象。

If you decide this option, you are stuck with the overhead of having two data objects that change roughly in parallel, but you also get the benefit of separating concerns (in case the Hibernate object should diverge) and the ease of a truly-immutable, equals-and-hashcode-overriding, session-agnostic, guaranteed-valid object that you can easily create for tests.

这篇关于如何编写一个测试友好的不可变值类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆