James
James

Reputation: 3184

How to mock a @Value class using Mockito?

I want to unit test the following class:

@Data
@AllArgsConstructor
public class MyClass {

   private MyValueClass valueObject;

   public BigDecimal someMethod(int startId, int endId) {

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

I tried to mock MyValueClass which looks like:

@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

   }

But when I run this junit (jupiter) test:

@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<>());
      ....
   }
}

I get the following error:

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)

But MyValueClass is not final. Why do I get this error? How can I mock this class?

Upvotes: 3

Views: 4993

Answers (2)

EricSchaefer
EricSchaefer

Reputation: 26370

A value object should never be mocked. It is just a immutable value after all (that's the reason why lombok makes it final). If it contains complicated logic or hidden mutable state (and therefore is not a real value object), you should not use @Value but use the individual pieces that you need (like @Getter).

Upvotes: 3

coloma1984
coloma1984

Reputation: 111

The Lombok annotation @Value on your MyValueClass makes your class final by default: lombok value feature. If you are using Mockito version 1, you cannot mock final classes: reference answer for mocking final classes. Try using PowerMockito or Mockito v2 mockito-inline: if you are using maven:

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

If you want to continue testing with mockito v1, try replacing @Value with @Data if it doesn't affect the performance.

Upvotes: 3

Related Questions