我使用MapStruct来映射我的实体,而我正在使用Mockito来模拟我的对象。
我想测试一个包含mapStruct映射的方法。问题是嵌套映射器在我的单元测试中始终为null(在应用程序中运行良好)
这是我的映射器声明:
@Mapper(componentModel = "spring", uses = MappingUtils.class)
public interface MappingDef {
UserDto userToUserDto(User user)
}
这是我的嵌套映射器
@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
我不想制作mappingDef
和mappingUtils
@Mock
所以我不需要在每个用例中做when(mappingDef.userToUserDto(user)).thenReturn(userDto)
强制MapStruct使用构造函数注入生成实现
@Mapper(componentModel = "spring", uses = MappingUtils.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface MappingDef {
UserDto userToUserDto(User user)
}
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface MappingUtils {
//.... other mapping methods used by userToUserDto
使用构造函数注入,以便您可以使用映射器构造测试中的类。
@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)
}
测试SomeClass。注意:它不是您在此处测试的映射器,因此可以模拟映射器。
@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
}
在真正的单元测试中,也要测试映射器。
@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)..
}
所以,试试这个:
Maven的:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
@ComponentScan(basePackageClasses = NoteServiceTest.class)
@Configuration
public class NoteServiceTest {
@Autowired
private SomeClass someClass;
private ConfigurableApplicationContext context;
@Before
public void springUp() {
context = new AnnotationConfigApplicationContext( getClass() );
context.getAutowireCapableBeanFactory().autowireBean( this );
}
@After
public void springDown() {
if ( context != null ) {
context.close();
}
}
@test
public void someTest(){
UserDto userDto = someClass.myMethodToTest();
//and here some asserts
}
更好的是一直使用构造函数注入...也在SomeClass
并使用@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
..然后你不需要在你的测试用例中进行弹簧/弹簧模拟。