如何在春季模拟ModelMapper?

时间:2020-04-12 12:31:33

标签: java spring testing junit mockito

我正在尝试为我的服务层编写单元测试:

@SpringBootTest
class ClinicServiceTest {

@Mock
private ProcedureRepository procedureRepository;
@InjectMocks
private ClinicService clinicService;

@Test
void setProcedureStatus() {
    when(procedureRepository.findById(1L)).thenReturn(Optional.of(initialEntity));
    when(procedureRepository.saveAndFlush(expectedEntity)).thenReturn(expectedEntity);
    Procedure assertProcedure = clinicService.setProcedureStatus(1L, "CANCELED");
  }
}

当我调用setProcedureStatus方法时,它会抛出NullPointerException,因为我的服务类使用了Spring自动装配的ModelMapper:

@Service
@RequiredArgsConstructor
public class ClinicService {

private final ProcedureRepository procedureRepository;
private final ModelMapper modelMapper;

public Procedure setProcedureStatus(Long procedureId, String status) {
    ...
    return modelMapper.map(procedureEntity, Procedure.class);
}

}

单元测试不会引发Spring上下文,这就是当我从测试中调用ModelMapper时,其在Service中为null的原因。有办法解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

您要编写单元测试,以便不应引发弹簧上下文。单元测试比集成测试(通常需要提高Spring上下文)的测试速度最快。当涉及单元测试时,您要测试应用程序的 unit 部分。

在这种情况下,由于未初始化ModelMapper,因此获得了NPE。

我没有看到您在哪里创建ClinicService,但是有一个示例可以避免这种NPE:

@Test
void setProcedureStatus() {
    when(procedureRepository.findById(1L)).thenReturn(Optional.of(initialEntity));
    when(procedureRepository.saveAndFlush(expectedEntity)).thenReturn(expectedEntity);
    // Initialize ClinicService with mocked procedeRepository but real ModelMapper
    ClinicService clinicService = new ClinicService(procedureRepository, new ModelMapper(), ... other dependencies );
    Procedure assertProcedure = clinicService.setProcedureStatus(1L, "CANCELED");
}

或者您也可以模拟ModelMapper。

另一种方法是使用MockitoJunitRunner并在如下所示的测试下初始化您的类:

@RunWith(MockitoJUnitRunner.class)
 public class ExampleTest {

     @Mock
     private ModelMapper modelMapper;

     @Mock
     private Repository repository;

     @InjectMocks
     private ClinicService classUnderTest;

由于依赖注入,您的代码测试起来更加简单,因为您可以使用通过构造函数传递的依赖来创建服务。