我正在尝试为以下控制器编写单元测试:
@RestController
@RequestMapping(value = ENDPOINT_URL)
public class MainController extends RestControllerBase {
MainService mainService;
public MainController(MainService mainService) {
this.mainService = mainService;
}
@GetMapping
public ResponseEntity<List<MainDataDto>> getDashboardData() {
checkPermission();
List<MainDataDto> result = mainService.getData();
return ResponseEntity.ok().body(result);
}
}
这是我到目前为止的单元测试:
class MainControllerTest {
MainController mainController;
@Test
public void test_getDashboardData_shouldReturn200Response() {
MainService mainService = Mockito.mock(MainService.class);
mainController = new MainController(mainService);
List<MainDataDto> mockData = List.of(new MainDataDto());
when(mainService.getData()).thenReturn(mockData);
Assertions.assertEquals(HttpStatus.OK, mainController.getDashboardData().getStatusCode());
}
当我运行此单元测试时,出现以下异常:
java.lang.NullPointerException: Cannot invoke "org.springframework.security.core.Authentication.getPrincipal()" because the return value of "org.springframework.security.core.context.SecurityContext.getAuthentication()" is null
这个异常来自
checkPermission
,它是RestControllerBase
类中的受保护方法。我无法更改此方法的访问修饰符。
我是编写单元测试的新手,所以我尝试一次做一点,这样我就能理解我在做什么。由于例外,我想“弄清楚如何处理”
checkPermission
并且(以我有限的理解)我认为我可以/应该以某种方式模拟这种方法,或者类似于通过我的这一部分的方法控制器方法结束。
由于此方法受到保护,更改我的单元测试的最佳方法是什么,这样我就不会再出现上述异常了?
作为短期解决方案,单元测试可以spy于
MainController
,例如:
mainController = Mockito.spy(new MainController(mainService));
允许模拟被测类的某些行为。 例如:
doNothing().when(mainController).checkPermission();
但是,由于需要测试的类的一部分不再被测试(因为它的行为被模拟),听起来该类应该被重构。 例如,无论
checkPermission()
正在做什么都可以移动到它自己的服务/组件类,并像MainService
一样注入到控制器中。 这将通过新类的模拟来简化单元测试设置,其中测试验证了新类被调用。