mockito MapStruct:模拟嵌套Map器

a64a0gku  于 2022-11-08  发布在  其他
关注(0)|答案(5)|浏览(235)

我用MapStructMap实体,我用Mockito模拟对象。
我想测试一个包含mapStructMap的方法。问题是嵌套的Map器在我的单元测试中总是空的(在应用程序中运行良好)
这是我的Map器声明:

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

这是我的嵌套Map器

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

这是我想测试的方法:

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

这是我的单元测试:

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

mappingDef已正确插入,但mappingUtils始终为空

否认者:这不是this question的副本。他正在使用@Autowire,因此他正在加载Spring上下文,因此他正在进行集成测试。我正在进行单元测试,因此我不使用@Autowired

我不想生成mappingDefmappingUtils@Mock,因此我不需要在每个用例中都执行when(mappingDef.userToUserDto(user)).thenReturn(userDto)

roejwanj

roejwanj1#

如果您愿意使用Spring测试工具,使用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
    )
}
nmpmafwu

nmpmafwu2#

强制MapStruct使用构造函数注入生成实现
第一个
使用构造函数注入,这样就可以用Map器构造测试中的类。

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

测试某个类。注意:您在这里测试的不是Map器,因此Map器可以被模仿。

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

在一个真正的单元测试中,也要测试Map器。

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

amrnrhlw3#

作为Sjaak’s answer的一个变体,现在可以依靠MapStruct本身来检索实现类,同时通过正确使用泛型来避免强制转换:

Class<? extends MappingDef> mapperClass = Mappers.getMapperClass(MappingDef.class);
Constructor<? extends MappingDef> constructor = mapperClass.getConstructor(MappingUtils.class);
MappingDef mappingDef = constructor.newInstance(Mappers.getMapper(MappingUtils.class));

通过检查构造函数,找到它需要的所有Map器作为参数,并递归地解析这些Map器,甚至可以使它完全通用。

t0ybt7op

t0ybt7op4#

所以,试试这个:
玛文:
第一个
更好的方法是一直使用构造函数注入......同样在SomeClass中,通过使用@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)......那么在您的测试用例中就不需要spring / spring模拟。

mwg9r5ms

mwg9r5ms5#

如前所述,您可以将injectionStrategy = InjectionStrategy.CONSTRUCTOR用于使用其他Map器的Map器(在本例中为MappingDef)。
而且比在考干脆:

@Spy
MappingUtils mappingUtils = Mappers.getMapper(MappingUtils.class);

@Spy
MappingDef mappingDef = new MappingDefImpl(mappingUtils);

也许不是最优雅的,但它的工作。

相关问题