我有這個要測驗的 Controller 類:
public class AuthController implements AuthApi {
private final UserService service;
private final PasswordEncoder encoder;
@Autowired
public AuthController(UserService service, PasswordEncoder encoder) {
this.service = service;
this.encoder = encoder;
}
@Override
public ResponseEntity<SignedInUser> register(@Valid NewUserDto newUser) {
Optional<SignedInUser> createdUser = service.createUser(newUser);
LoggerFactory.getLogger(AuthController.class).info(String.valueOf(createdUser.isPresent()));
if (createdUser.isPresent()) {
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser.get());
}
throw new InsufficientAuthentication("Insufficient info");
}
這是我的單元測驗:
@ExtendWith(MockitoExtension.class)
@JsonTest
public class AuthControllerTest {
@InjectMocks
private AuthController controller;
private MockMvc mockMvc;
@Mock
private UserService service;
@Mock
private PasswordEncoder encoder;
private static SignedInUser testSignedInUser;
private JacksonTester<SignedInUser> signedInTester;
private JacksonTester<NewUserDto> dtoTester;
@BeforeEach
public void setup() {
ObjectMapper mapper = new AppConfig().objectMapper();
JacksonTester.initFields(this, mapper);
MappingJackson2HttpMessageConverter mappingConverter = new MappingJackson2HttpMessageConverter();
mappingConverter.setObjectMapper(mapper);
mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setControllerAdvice(new RestApiErrorHandler())
.setMessageConverters(mappingConverter)
.build();
initializeTestVariables();
}
private void initializeTestVariables() {
testSignedInUser = new SignedInUser();
testSignedInUser.setId(1L);
testSignedInUser.setRefreshToken("RefreshToken");
testSignedInUser.setAccessToken("AccessToken");
}
@Test
public void testRegister() throws Exception {
NewUserDto dto = new NewUserDto();
dto.setEmail("[email protected]");
dto.setPassword("ThisIsAPassword");
dto.setName("ThisIsAName");
// Given
given(service.createUser(dto)).willReturn(Optional.of(testSignedInUser));
// When
MockHttpServletResponse res = mockMvc.perform(post("/api/v1/auth/register")
.contentType(MediaType.APPLICATION_JSON)
.content(dtoTester.write(dto).getJson()).characterEncoding("utf-8").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andReturn()
.getResponse();
// Then
assertThat(res.getStatus()).isEqualTo(HttpStatus.CREATED.value());
assertThat(res.getContentAsString()).isEqualTo(signedInTester.write(testSignedInUser).getJson());
}
}
問題:
測驗失敗,因為我收到“資訊不足”訊息,因為isPresent()永遠不會正確,即使
given(service.createUser(dto)).willReturn(Optional.of(testSignedInUser))已經存在。當我嘗試service.createUser(dto)在測驗方法中登錄時,它isPresent()總是正確的。當我嘗試 在控制器方法中登錄時,它總是錯誤的。
我試過的:
我懷疑這是因為不知何故我
mockMvc的配置錯誤,所以我嘗試添加@AutoConfigureMockMvc,但最終告訴我“沒有為'mockMvc'配置bean”。我試圖將UserService模擬更改為但沒有用的實作類。
請幫忙,我對 Spring 的單元測驗很陌生。謝謝!
uj5u.com熱心網友回復:
問題在于您發現 Mockito 嘲笑:
given(service.createUser(dto)).willReturn(Optional.of(testSignedInUser))
具體來說,您指示模擬物件在接收到等于的引數時service回傳。但是,根據 的 方法的 實作,這可能永遠不會發生。例如,它僅在參考同一個實體而不是比較成員變數的值時才回傳。因此,當通過 a 時,它首先被序列化,然后由物件映射器再次序列化,因此即使它的成員變數具有相同的值,除非您還覆寫該方法,否則物件不會被視為相等。Optional.of(testSignedInUser)dtoequals()NewUserDtotruedtomockMvcequals()
作為替代方案,您可以放松模擬以回傳傳遞了Optional.of(testSignedInUser)if any()引數:
given(service.createUser(any())).willReturn(Optional.of(testSignedInUser))
或者如果引數是 A()特定類:
given(service.createUser(isA(NewUserDto.class))).willReturn(Optional.of(testSignedInUser))
但一般來說,從測驗的角度來看,最好是明確的以避免誤報,因此我建議盡可能仔細檢查和/或覆寫該NewUserDto#equals()方法。
uj5u.com熱心網友回復:
感謝@matsev 的回答,我能夠解決一半的問題,但也有這樣的事情:
@Controller
public class AuthController implements AuthApi {
private final UserService service;
private final PasswordEncoder encoder;
// ...
}
我將服務欄位保留為final,這不允許 Mockito 注入或改變依賴項。洗掉后final,我現在可以進行測驗了。
編輯:請參閱此執行緒以了解 Mockito 的解決方法,@InjectMocks 最終欄位的奇怪行為
編輯 2:按照設計,Mockito 不會將模擬注入最終欄位:https ://github.com/mockito/mockito/issues/352
這樣做會違反其他 API 并可能導致問題。解決此問題的一種方法是僅使用建構式注入 remove @InjectMocks,然后您就可以使用final欄位。
// No InjectMocks
private AuthController controller;
@Mock
private UserService service;
@Mock
private PasswordEncoder encoder;
@BeforeEach
public void setup() {
controller = new AuthController(service, encoder);
// ...
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/494558.html
