Search code examples
javaunit-testingmockitomapstruct

MapStruct : mocking nested mapper


I using MapStruct to map my entities, and I'm mocking my objects using Mockito.

I want to test a method that contains a mapping with mapStruct. The problem is the nested mapper is always null in my unit tests (works well in the application)

this is my mapper declaration :

@Mapper(componentModel = "spring", uses = MappingUtils.class)
public interface MappingDef {
     UserDto userToUserDto(User user)
}

this is my nested mapper

@Mapper(componentModel = "spring")
public interface MappingUtils {
    //.... other mapping methods used by userToUserDto

this is the method that I want to test :

@Service
public class SomeClass{
        @Autowired
        private MappingDef mappingDef;

        public UserDto myMethodToTest(){

        // doing some business logic here returning a user
        // User user = Some Business Logic

        return mappingDef.userToUserDto(user)
}

and this is my unit test :

@RunWith(MockitoJUnitRunner.class)
public class NoteServiceTest {

    @InjectMocks
    private SomeClass someClass;
    @Spy
    MappingDef mappingDef = Mappers.getMapper(MappingDef.class);
    @Spy
    MappingUtils mappingUtils = Mappers.getMapper(MappingUtils.class);

    //initMocks is omitted for brevity

    @test
    public void someTest(){
         UserDto userDto = someClass.myMethodToTest();

         //and here some asserts
    }

mappingDef is injected correctly, but mappingUtils is always null

Disclamer : this is not a duplicate of this question. He is using @Autowire so he is loading the spring context so he is doing integration tests. I'm doing unit tests, so I dont to use @Autowired

I dont want to make mappingDef and mappingUtils @Mock so I don't need to do when(mappingDef.userToUserDto(user)).thenReturn(userDto) in each use case


Solution

  • If you are willing to use Spring test util, it's fairly easy with org.springframework.test.util.ReflectionTestUtils.

    MappingDef mappingDef = Mappers.getMapper(MappingDef.class);
    MappingUtils mappingUtils = Mappers.getMapper(MappingUtils.class);
    
    ...
    
    // Somewhere appropriate
    @Before
    void before() {
        ReflectionTestUtils.setField(
            mappingDef,
            "mappingUtils",
            mappingUtils
        )
    }