Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Junit test for mapstruct abstract mapper injected via Spring

Tags:

I'm using MapStruct, mapstruct-jdk8 version 1.1.0.Final and defining abstract class that I inject via Spring.

I'm looking at how to be able to test them via Junit Test ? I've basicaly a main mapper that will use 2 sub mappers

@Mapper(componentModel = "spring", uses = {SubMapper1.class, SubMapper2.class}) public abstract class MainMapper {    @Mapping(target = "field1", qualifiedByName = {"MyMapper2Name", "toEntity"})   public abstract MyEntity toEntity(MyDto pDto);    public MyDto fromEntity(MyEntity pEntity) {      // Specific code, hence why I use Abstract class instead of interface.    } } 

I've tried several things but can't get the mapper to be instancied correctly to test it.

@RunWith(SpringRunner.class) public class MainMapperTest {      private MainMapper service = Mappers.getMapper(MainMapper.class);      @Test     public void testToEntity() throws Exception { ..... 

java.lang.RuntimeException: java.lang.ClassNotFoundException: Cannot find implementation for com.mappers.MainMapper

I've also tried via @InjectMock but no dice either.

Cannot instantiate @InjectMocks field named 'service'. You haven't provided the instance at field declaration so I tried to construct the instance. However, I failed because: the type 'MainMapper is an abstract class.

And via Spring @Autowired

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mappers.MainMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

I'm guessing this might have to do with annotation processor, and mapper not being generated when I launch test. I found this class as example.

However the class AnnotationProcessorTestRunner doesn't seems to be available before 1.2 which has no final release yet.

So my question is how do I write Junit tests to test my mapstruct abstract class mapper that I use via Spring injection in my code.

like image 487
TheBakker Avatar asked Jul 24 '17 08:07

TheBakker


2 Answers

In response to @Richard Lewan comment here is how I declared my test class for the abstract class ConfigurationMapper using 2 subMappers

@RunWith(SpringRunner.class) @SpringBootTest(classes = {ConfigurationMapperImpl.class, SubMapper1Impl.class, SubMapper2Impl.class}) public class ConfigurationMapperTest { 

You use the Impl generated classes in the SpringBootTest annotation and then inject the class you want to test:

@Autowired private ConfigurationMapper configurationMapper; 

Let me know if you need more info, but from there it's straightforward. I didn't mock the subMapper, as it was better for me to test all the mapping process at once.

like image 93
TheBakker Avatar answered Sep 19 '22 04:09

TheBakker


Addition to @TheBakker's answer: as a lighter alternative to @SpringBootTest you can use @ContextConfiguration, if you do not require the whole SpringBoot stack. His example would look like this:

@ExtendWith(SpringExtension.class) // JUnit 5 @ContextConfiguration(classes = {             ConfigurationMapperImpl.class,             SubMapper1Impl.class,             SubMapper2Impl.class         }) public class ConfigurationMapperTest { ... 

With JUnit 4 use annotation RunWith instead of ExtendWith:

@RunWith(SpringRunner.class)       // JUnit 4 ... 
like image 31
t0r0X Avatar answered Sep 21 '22 04:09

t0r0X