【问题标题】:How to write Junit test for mapstruct abstract mapper injected via Spring如何为通过 Spring 注入的 mapstruct 抽象映射器编写 Junit 测试
【发布时间】:2017-12-29 17:34:16
【问题描述】:

我正在使用 MapStruct,mapstruct-jdk8 版本 1.1.0.Final 并定义我通过 Spring 注入的抽象类。

我正在研究如何通过 Junit Test 测试它们? 我基本上有一个将使用 2 个子映射器的主映射器

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

我尝试了几件事,但无法正确实例化映射器以对其进行测试。

@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: 找不到 com.mappers.MainMapper 的实现

我也尝试过@InjectMock,但也没有骰子。

无法实例化名为“服务”的 @InjectMocks 字段。你没有 在字段声明中提供了实例,所以我尝试构建 实例。但是,我失败了,因为:'MainMapper 类型是 一个抽象类。

通过 Spring @Autowired

原因: org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 'com.mappers.MainMapper' 类型的合格 bean 可用:预期 至少 1 个符合自动装配候选资格的 bean。依赖 注释: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

我猜这可能与注释处理器有关,并且在我启动测试时未生成映射器。 我找到了this class as example

然而,AnnotationProcessorTestRunner 类似乎在 1.2 之前不可用,还没有最终版本。

所以我的问题是如何编写 Junit 测试来测试我在代码中通过 Spring 注入使用的 mapstruct 抽象类映射器。

【问题讨论】:

    标签: spring unit-testing junit spring-test mapstruct


    【解决方案1】:

    作为对@Richard Lewan 评论的回应,这里是我如何使用 2 个子映射器为抽象类 ConfigurationMapper 声明我的测试类

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

    你在SpringBootTest注解中使用Impl生成的类,然后注入你要测试的类:

    @Autowired
    private ConfigurationMapper configurationMapper;
    

    如果您需要更多信息,请告诉我,但从那里开始就很简单了。 我没有模拟 subMapper,因为我最好一次测试所有映射过程。

    【讨论】:

      【解决方案2】:

      除了@TheBakker 的回答:作为@SpringBootTest 的更轻量级替代品,如果您不需要整个SpringBoot 堆栈,您可以使用@ContextConfiguration。他的示例如下所示:

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

      在 JUnit 4 中使用注释 RunWith 而不是 ExtendWith

      @RunWith(SpringRunner.class)       // JUnit 4
      ...
      

      【讨论】:

      • 如果您正在编写单元测试而不是集成测试,这是最有效的方法。请注意,如果您使用的是 junit5,则需要将 @RunWith(SpringRunner.class) 替换为 @ExtendWith(SpringExtension.class)
      【解决方案3】:

      您有多个问题:

      1. 您应该只使用Mappers#getMapper(Class) 和默认的componentModel,否则映射器将无法正确实例化。如果您在那里获得RuntimeException,则表示未生成实现类。确保您的设置正确
      2. 您需要针对实现 MainMapperImpl 而不是针对抽象类进行测试。
      3. 如果您想使用 spring bean 进行测试,那么您需要使用正确的 ComponentScan 并确保实现和使用的映射器可以自动装配。

      您链接的类是错误的测试类,与您的测试用例无关。看看this spring 集成的集成测试用例。

      AnnotationProcessorTestRunner 是我们测试的一部分,用于测试注释处理器,从一开始就存在。它不是版本的一部分。

      【讨论】:

        【解决方案4】:

        假设:

        • 您的MainMapper 映射器被注入@Component ConverterUsingMainMapper

        您可以使用以下示例:

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

        【讨论】:

        • 这是否意味着所有其他已自动装配的非映射器依赖项也需要在 Config 中定义为 bean?
        • 我们需要在测试类中自动装配吗?我们不能使用@InjectMocks 吗?
        【解决方案5】:

        使用 Mockito:

        @Spy
        private EntityMapper entityMapper = Mappers.getMapper(MyMapper.class);
        

        记住在你的测试类中注入模拟,例如:

        @InjectMocks
        private MyClassUnderTest myClassUnderTest
        

        【讨论】:

        • 谢谢你用@Spy 注释拯救了我的一天。它对 junit4 测试开发人员来说是个好主意。因为官方文档上没有junit 4的解决方案。
        猜你喜欢
        • 2021-01-04
        • 1970-01-01
        • 2023-01-15
        • 1970-01-01
        • 1970-01-01
        • 2017-11-03
        • 2019-05-05
        • 2023-01-31
        • 1970-01-01
        相关资源
        最近更新 更多