How to test Service class methods which uses Mapstruct mappers in Springboot?

Viewed 550
@Mapper(uses = SomeMapper.class,imports = Date.class)
public interface DomainModelMapper {    
    Model domainToModel(Domain domain);
    
    @Mapping(target="dateUpdated", source="dateUpdated" ,defaultExpression = "java(Date.from(java.time.OffsetDateTime.now().toInstant()))")
    @Mapping(target="id.key",source="id.key",defaultExpression = "java(com.datastax.driver.core.utils.UUIDs.timeBased())")
    Domain modelToDomain(Model model);
}

I have a mapper class to do some Date conversions

public class SomeMapper {

    public Date OffsetDateTimeToDate(OffsetDateTime offsetDateTime) {
        return offsetDateTime != null ? Date.from(offsetDateTime.toInstant()):null;
    }

    public OffsetDateTime DateToOffsetDateTime(Date date) {
        return date != null ? date.toInstant().atOffset(ZoneOffset.UTC) : null;
    }
}

This is my service class where I use DomainModelMapper

@Service
public class SomeServiceImpl implements SomeService {
    
    @Autowired
    someRepository someRepository;
    
    
    private final DomainModelMapper domainToModelMapper = 
            Mappers.getMapper(DomainModelMapper.class);

    @Override
    public Model saveSomething(Model model) {
        return DomainModelMapper.domainToModel(someRepository
                .save(DomainModelMapper.modelToDomain(model)));
    }

How can I unit test saveSomething(Model model) method? How I can inject Mapstruct classes or mock them?

1 Answers

If you make the @Mapper interface as a Spring-based component model, then it can be autowired through @Autowired annotation. Read more at 4.2. Using dependency injection

@Mapper(uses = SomeMapper.class,imports = Date.class, componentModel = "spring")
public interface DomainModelMapper { 
    // IMPLEMENTATION
}
@Service
public class SomeServiceImpl implements SomeService {
    
    @Autowired
    SomeRepository someRepository;
    
    @Autowired
    DomainModelMapper domainModelMapper;

    // THE REST OF THE IMPLEMENTATION
}

The testing becomes fairly easy since all the beans can be also injected in the @SpringBootTest with the @Autowired annotation.

  • The DomainModelMapper can be autowired and used in the unit test as is and rely on its implementation
  • The SomeRepository shall be either mocked using @MockBean which overwrites an existing bean or creates a new one if none of that type exists... or autowired as in the implementation if you use an in-memory database for the testing phase, such as H2.

In any case, the test class will be ready for testing.

@SpringBootTest
public class SomeServiceTest {
    
    @Autowired // or @MockBean
    SomeRepository someRepository;
    
    @Autowired // no need to mock it
    DomainModelMapper domainModelMapper;

    @Test
    public void test() {
        // TEST
    }
}
Related