我試圖用 Junit5 和 mockito 撰寫一個單元測驗,但是當被測驗的方法呼叫另一個嵌套在自身中的方法時,我得到了 NullPointerException。在除錯時,我在該方法引數上得到“找不到區域變數”。這是代碼:
測驗類:
@ExtendWith(MockitoExtension.class)
class DeckServiceImplTest {
@Mock
private UserServiceImpl userService;
@Mock
private DeckRepository deckRepository;
@InjectMocks
private DeckServiceImpl deckService;
@BeforeEach
void setUp() {
deckService = new DeckServiceImpl(deckRepository, userService);
}
@Test
@DisplayName("when deck id is provided returned deck should be correct")
@WithMockUser(username = "user", password = "user", roles = "USER")
public void whenDeckIdIsProvidedThenRetrievedDeckIsCorrect() {
//given
DeckDto testDeck = null;
User deckBaseEntityOwner = new User();
deckBaseEntityOwner.setEmail("[email protected]");
deckBaseEntityOwner.setId(10L);
deckBaseEntityOwner.setRole(Role.ADMIN);
Deck deckBaseEntity = new Deck();
deckBaseEntity.setName("deck name");
deckBaseEntity.setAccessLevel(AccessLevel.PUBLIC.getAccessLevel());
deckBaseEntity.setOwner(deckBaseEntityOwner);
deckBaseEntity.setId(1L);
//when
when(deckRepository.findById(anyLong())).thenReturn(of(deckBaseEntity));
testDeck = deckService.findById(1L);
//then
verify(deckRepository).findById(anyLong());
assertNotNull(testDeck);
assertEquals("deck name", testDeck.getName());
assertEquals(10L, testDeck.getOwnerId());
assertEquals("[email protected]", testDeck.getOwnerEmail());
assertEquals(AccessLevel.PUBLIC.getAccessLevel(), testDeck.getAccessLevel());
}
}
經測驗的服務方式:
@Override
public DeckDto findById(Long id) throws ElementNotFoundByIdException, PermissionDeniedException {
Deck deck = deckRepository.findById(id).orElseThrow(() -> new ElementNotFoundByIdException(
CAN_NOT_FIND_DECK_BY_ID_ERROR_MESSAGE.getMessage() id,
CAN_NOT_FIND_DECK_BY_ID_ERROR_CODE.getValue()
));
validatePermissionByDeckAccessLevel(deck);
return modelMapper.map(deck, DeckDto.class);
}
private void validatePermissionByDeckAccessLevel(Deck deck) throws PermissionDeniedException {
ArrayList<? extends GrantedAuthority> authorities = new ArrayList<>(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
if (!SecurityContextHolder.getContext().getAuthentication().getName().equals(deck.getOwner().getEmail())
&& !deck.getAccessLevel().equals(AccessLevel.PUBLIC.getAccessLevel())
&& !authorities.get(0).getAuthority().equals(Role.ADMIN.getRole())) {
throw new PermissionDeniedException(
USER_DONT_HAVE_PERMISSIONS_ERROR_MESSAGE.getMessage(),
USER_DONT_HAVE_PERMISSIONS_ERROR_CODE.getValue()
);
}
}
每次它進入validatePermissionByDeckAccessLevel(Deck deck)方法時,它都會在甲板欄位上拋出 NPE,即使我確定(我仔細檢查過)我傳遞了非空值。在嘗試除錯即時訊息時,螢屏上顯示了訊息。
validatePermissionByDeckAccessLevel(Deck deck)所做的只是檢查角色或電子郵件(盡管它已經過測驗并且可以作業,但這并不重要)。
uj5u.com熱心網友回復:
你deck
的沒問題,你已經用AccessLevel
and存根甲板Owner
,并且所有者已經有了email
。
關于這一點:
在除錯時,我在該方法引數上得到“找不到區域變數”
它不應該相關,您可能只是在變數不存在的地方放置了錯誤的斷點。
問題應該來自以下幾行之一:
SecurityContextHolder.getContext().getAuthentication().getAuthorities()
SecurityContextHolder.getContext().getAuthentication().getName()
authorities.get(0).getAuthority()
除了上述主要內容之外,您還可以在代碼中改進以下內容:
- 您已經使用過
@InjectMocks
,所以這一行是多余的:deckService = new DeckServiceImpl(deckRepository, userService);
- 你用了實作,雖然沒有問題,但最好用介面:
private UserServiceImpl userService;
- 您應該通過 api 進行測驗,而不是實作:
private DeckServiceImpl deckService;
DeckDto testDeck = null;
這條線是不必要的,你可以這樣做:DeckDto testDeck = deckService.findById(1L);
- 避免使用
anyLong()
- 你應該知道你要測驗什么,所以你應該準確地測驗你想要測驗的行為。 - 你呼叫
SecurityContextHolder.getContext().getAuthentication()
了兩次,最好為它宣告一個變數,然后使用getAuthorities
orgetName
- 這一行:(
List
用于宣告變數而不是ArrayList
)
ArrayList<? extends GrantedAuthority> authorities = new ArrayList<>(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
可以改為:
List<? extends GrantedAuthority> authorities = new ArrayList<>(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/470366.html