MapStruct:模拟嵌套映射器

ihe*_*heb 7 java unit-testing mockito mapstruct

我使用 MapStruct 来映射我的实体,并且我正在使用 Mockito 模拟我的对象。

我想测试一个包含 mapStruct 映射的方法。问题是嵌套映射器在我的单元测试中始终为空(在应用程序中运行良好)

这是我的映射器声明:

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

这是我的嵌套映射器

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

这是我要测试的方法:

@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)
}
Run Code Online (Sandbox Code Playgroud)

这是我的单元测试:

@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
    }
Run Code Online (Sandbox Code Playgroud)

mappingDef被正确注入,但mappingUtils始终为空

免责声明:这不是这个问题的重复。他正在使用@Autowire,因此他正在加载 spring 上下文,因此他正在进行集成测试。我在做单元测试,所以我不使用@Autowired

我不想做mappingDefmappingUtils @Mock所以我不需要when(mappingDef.userToUserDto(user)).thenReturn(userDto)在每个用例中做

Lee*_*eol 14

如果您愿意使用 Spring test util,那么使用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
    )
}
Run Code Online (Sandbox Code Playgroud)


Sja*_*aak 10

强制 MapStruct 通过构造函数注入生成实现

@Mapper(componentModel = "spring", uses = MappingUtils.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface MappingDef {
     UserDto userToUserDto(User user)
}
Run Code Online (Sandbox Code Playgroud)
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface MappingUtils {
    //.... other mapping methods used by userToUserDto
Run Code Online (Sandbox Code Playgroud)

使用构造函数注入,以便您可以使用映射器构造被测试的类。

@Service
public class SomeClass{

        private final MappingDef mappingDef;

        @Autowired
        public SomeClass(MappingDef mappingDef) {
            this.mappingDef = mappingDef; 
        }

        public UserDto myMethodToTest(){

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

        return mappingDef.userToUserDto(user)
}

Run Code Online (Sandbox Code Playgroud)

测试一些类。注意:它不是您在这里测试的映射器,因此可以模拟映射器。

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {

    private SomeClass classUnderTest;

    @Mock
    private MappingDef mappingDef;

    @Before init() {
        classUnderTest = new SomeClass(mappingDef);
        // defaultMockBehaviour: 
when(mappingDef.userToUserDto(anyObject(User.class).thenReturn(new UserDto());
    } 

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

         //and here some asserts
    }
Run Code Online (Sandbox Code Playgroud)

在真正的单元测试中,还要测试映射器。

@RunWith(MockitoJUnitRunner.class)
public class MappingDefTest {

  MappingDef classUnderTest;

  @Before
  void before() {
       // use some reflection to get an implementation
      Class aClass = Class.forName( MappingDefImpl.class.getCanonicalName() );
      Constructor constructor =
        aClass.getConstructor(new Class[]{MappingUtils.class});
      classUnderTest = (MappingDef)constructor.newInstance( Mappers.getMapper( MappingUtils.class ));
  }

  @Test
  void test() {
     // test all your mappings (null's in source, etc).. 
  }


Run Code Online (Sandbox Code Playgroud)


GJo*_*nes 7

无需使用反射。对我来说最简单的方法如下:

@RunWith(MockitoJUnitRunner.class)
public class NoteServiceTest {

@InjectMocks
private SomeClass someClass;

@Spy
@InjectMocks
MappingDef mappingDef = Mappers.getMapper(MappingDef.class);
@Spy
MappingUtils mappingUtils = Mappers.getMapper(MappingUtils.class);
Run Code Online (Sandbox Code Playgroud)

然而,这仅适用于嵌套映射器的第一层。如果您有一个使用第三个映射器的映射器,那么您需要使用将ReflectionTestUtils第三个映射器注入到第二个映射器中。