How to write Junit test for mapstruct abstract map

2019-04-22 20:50发布

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.

3条回答
霸刀☆藐视天下
2楼-- · 2019-04-22 21:12

Assumming that:

  • Your MainMapper mapper gets injected into @Component ConverterUsingMainMapper

You can use the following example:

@RunWith(SpringRunner.class)
@ContextConfiguration
public class ConsentConverterTest {

    @Autowired
    MainMapper MainMapper;

    @Autowired
    ConverterUsingMainMapper converter;

    @Configuration
    public static class Config {

        @Bean
        public ConverterUsingMainMapper converterUsingMainMapper() {
            return new ConverterUsingMainMapper();
        }

        @Bean
        public MainMapper mainMapper() {
            return Mappers.getMapper(MainMapper.class);
        }
    }


    @Test
    public void test1() {
        // ... your test.
    }

}
查看更多
戒情不戒烟
3楼-- · 2019-04-22 21:16

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 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.

查看更多
啃猪蹄的小仙女
4楼-- · 2019-04-22 21:30

You are having multiple issues:

  1. You should use Mappers#getMapper(Class) only with the default componentModel, otherwise the mapper will not be instantiated correctly. If you are getting the RuntimeException there it means that the implementation class was not generated. Make sure that you have a correct setup
  2. You need to test against the implementation MainMapperImpl and not against the abstract class.
  3. If you want to test with the spring bean then you need to be using correct ComponentScan and make sure that the implementation and the used mappers can be autowired.

The class you linked is a wrong test class and is not related to your test case. Have a look at this integration test case for spring integration.

The AnnotationProcessorTestRunner is part of our tests and is used to test the annotation processor and has been there since the beginning. It is not part of the releases.

查看更多
登录 后发表回答