如何使用 Mockito 模拟 @Value class?

How to mock a @Value class using Mockito?

我想对以下内容进行单元测试 class:

@Data
@AllArgsConstructor
public class MyClass {

   private MyValueClass valueObject;

   public BigDecimal someMethod(int startId, int endId) {

      List<BigDecimal> values = valueObject.get(startId, endId);
      
      ...

我试着模仿 MyValueClass 看起来像:

@Value //lombok annotation
public class MyValueClass {

   private List<Data> someData;

   public List<BigDecimal> get(int startId, int endId) {

       //code to get subset of someData with ids between startId and endId

   }

但是当我 运行 这个 junit (jupiter) 测试时:

@ExtendWith(MockitoExtension.class)
class MyClassTest {

   private MyClass myClass;

   @Mock
   private MyValueClass valueOjectMock;

   @BeforeEach
   public void setUp() {
      myClass= new myClass(valueOjectMock);
   }

   @Test
   void test() {
      when(valueOjectMock.get(1,5))
         .thenReturn(new ArrayList<>());
      ....
   }
}

我收到以下错误:

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class com.seasset.funds.performance.domain.FundReturns
Mockito cannot mock/spy because :
 - final class
    at org.mockito.junit.jupiter.MockitoExtension.beforeEach(MockitoExtension.java:153)

但是MyValueClass不是最终的。为什么会出现此错误?我怎样才能嘲笑这个 class?

您的 MyValueClass 上的 Lombok 注释 @Value 默认使您的 class 最终:lombok value feature. If you are using Mockito version 1, you cannot mock final classes: reference answer for mocking final classes。尝试使用 PowerMockito 或 Mockito v2 mockito-inline:如果您使用的是 maven:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.9.0</version>
    <scope>test</scope>
</dependency>

如果您想继续使用 mockito v1 进行测试,请在不影响性能的情况下尝试将 @Value 替换为 @Data。

永远不应模拟值对象。毕竟它只是一个不可变的值(这就是为什么 lombok 将其定为 final 的原因)。如果它包含复杂的逻辑或隐藏的可变状态(因此不是真正的值对象),则不应使用 @Value 而是使用您需要的各个部分(如 @Getter)。