我使用MapStruct映射我的实体,并使用Mockito模拟对象。
我想测试一种包含mapStruct映射的方法。 问题是嵌套映射器在我的单元测试中始终为空(在应用程序中运行良好)
这是我的映射器声明:
@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)
答案 0 :(得分:3)
如果您愿意使用 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
)
}
答案 1 :(得分:0)
因此,请尝试以下操作:
行家:
<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)
中使用。那么您就不需要在测试用例中使用spring / spring模拟了。
答案 2 :(得分:0)
强制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)..
}