It seems this is a well-documented issue here on Stackoverflow but it seems non of the solutions are working for me (if I am wrong I'd be glad if someone pointed me to a solution). I was following this tutorial on how to test Webflux controllers in Spring boot. I did what I believe is exactly what is in the tutorial but for some reason, I am getting the error below:
Wanted but not invoked:
wordRepository bean.save(
Word(word=test word, id=0, updatedAt=2022-04-11T01:19:10.275631, createdAt=2022-04-11T01:19:10.275631)
);
-> at com.freeman.hangman.controller.WordControllerImplTest.givenWordDTO_expectedCreateWord(WordControllerImplTest.kt:78)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
wordRepository bean.save(
Word(word=test word, id=0, updatedAt=2022-04-11T01:19:10.275631, createdAt=2022-04-11T01:19:10.275631)
);
-> at com.freeman.hangman.controller.WordControllerImplTest.givenWordDTO_expectedCreateWord(WordControllerImplTest.kt:78)
Actually, there were zero interactions with this mock.
This is my controller
@ExtendWith(SpringExtension::class)
@WebFluxTest(WordControllerImpl::class)
@Import(WordServiceImpl::class)
class WordControllerImplTest {
@Autowired
lateinit var webClient: WebTestClient
@MockBean
lateinit var wordService: WordServiceImpl
@MockBean
lateinit var wordRepository: WordRepository
private val CURRENT_DATE_TIME = LocalDateTime.now()
private val TEST_WORD_ID = 1
@Test
@WithMockUser(username = "[email protected]", authorities = ["ROLE_USER", "ROLE_ADMIN"], password = "pwd")
fun givenWordDTO_expectedCreateWord(){
val wordDto = WordDto(word = "test word", id = 0, createdAt = CURRENT_DATE_TIME.toString())
val word = Word("test word", 0, CURRENT_DATE_TIME, CURRENT_DATE_TIME)
`when`(wordRepository.save(word)).thenReturn(Mono.just(word))
webClient.mutateWith(csrf()).post()
.uri("/freeman-hangman/words/create")
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(wordDto))
.exchange()
.expectStatus()
.isCreated
verify(wordRepository, times(1)).save(word)//this is where the error is happening
}
}
Where can I be going wrong?
CodePudding user response:
If I understood correctly, WordServiceImpl
is kind of wrapper to WordRepository
. Every call to repository goes through service. Since you have mocked the service, those actions don't go to the repository.
If you want to assert repository interaction, don't mock WordServiceImpl
or use spy instead.
When you create a mock object of a class, you have to define its behavior, since the mocked object does not act as the original instance of the class.
You can use spy instead of mock which behaves like the original instance if you don't tell the otherwise via mocking its methods.
You can do either:
- Delete
@MockBean lateinit var wordService: WordServiceImpl
or - Use
@SpyBean
instead of@MockBean
forWordServiceImpl
But if I were you, I would choose the first option, since it doesn't really make sense to use @SpyBean
for an object that you didn't use