我正在尝试为我的服务层编写单元测试:
@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的原因。有办法解决这个问题吗?
答案 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;
由于依赖注入,您的代码测试起来更加简单,因为您可以使用通过构造函数传递的依赖来创建服务。