I want to mock this webclient post call.
Service
fun <T : Any> post(uri: String, body: Any, responseType: Class<T>): Class<T>? {
return webClient.post()
.uri(uri)
.bodyValue(body)
.retrieve()
.bodyToMono(responseType::class.java)
.block()
}
I am getting a null pointer exception when I am mocking bodyToMono using a Class<T> generic.
ServiceTest
#Mock
lateinit var mockWebClient: WebClient
#Autowired
private lateinit var onelinkRestClient: OnelinkRestClient
#Mock
private lateinit var requestHeadersMock: WebClient.RequestBodyUriSpec
#Mock
private lateinit var responseMock: WebClient.ResponseSpec
#Mock
private lateinit var requestBodyUriMock: WebClient.RequestBodyUriSpec
#Mock
private lateinit var requestBodyMock: WebClient.RequestBodySpec
#BeforeEach
fun setUp() {
webclient = Service(mockWebClient)
}
val uri = "/path"
`when`(mockWebClient.post()).thenReturn(requestBodyUriMock)
`when`(requestBodyUriMock.uri(uri)).thenReturn(requestBodyMock)
`when`(requestBodyMock.bodyValue((requestDTO))).thenReturn(requestHeadersMock)
`when`(requestHeadersMock.retrieve()).thenReturn(responseMock)
`when`(responseMock.bodyToMono(ResponseDTO::class.java)).thenReturn(Mono.just(responseDTO))
val response = webclient.post<ResponseDTO>("/path", responseDTO, responseDTO::class.java)
When running serviceTest, it gives me an error:
java.lang.NullPointerException: Cannot invoke "reactor.core.publisher.Mono.block()" because the return value of "org.springframework.web.reactive.function.client.WebClient$ResponseSpec.bodyToMono(java.lang.Class)" is null
If I change it from generic Class<T> to a some Class defined it doesn't throw NPE
fun <T : Any> post(uri: String, body: Any, responseType: Class<T>): Class<T>? {
return webClient.post()
.uri(uri)
.bodyValue(body)
.retrieve()
.bodyToMono(responseType::class.java)
.block()
}
Insted of bodyToMono of responseType::class.java, when I do it with defined class, the testcase passes.
eg
.bodyToMono(abc::class.java)
I am trying to mock a generic class of type T Class<T> in bodyToMono.
I think your test is correct, but your function is wrong. It calls ::class on a Class instance, so you will always end up with a Class<Class<?>>.
Don't you want the following?
.bodyToMono(responseType)
or perhaps:
.bodyToMono(responseType.java)
(I don't know Kotlin well enough)
Related
struggling here, I have been stuck on this for about a week now, don't know how to get this working. I am trying to write a integration test to check if my introduced spring variable validation in my controller is working, but I am running into issues on how to exactly do this in kotlin.
With where I am now, I have all the dependencies autowired, and can pass the #AuthenticationPrincipal layer of my controller and the code executes, but if I debug, the userService which is being used for user retrieval, and has been autowired is null in the controller(not NPE but just null when debugging inside of the controller). It seems there is an issue with wiring in that service/dependency?
I have also tried the mvc.StandAloneSetup(UserController) and have gotten that to work with all the dependencies, but unfourtunately I had to abandon that approach, because I could not figure out how pass the #AuthenticationPrincipal.. #WithUSerDetails, #WithMockUser, #WithUser, none of which worked. Any advice onw hat I am doing wrong? New to kotlin so don't know much
Additionally I had some success with mappings that did not require authenticaiton, but the validation seemed to always spout random errors(error from previous test execution) issue with context clearing?
#RunWith(SpringJUnit4ClassRunner::class)
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("test")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
open class UsersControllerTest {
#Autowired lateinit var mockMvc: MockMvc
#Autowired lateinit var mapper: ObjectMapper
#Autowired private var db = testDatabase()
#Autowired private lateinit var userRepository: UserRepository
#Autowired private lateinit var dependency : dependency
#Autowired private lateinit var usersService : UsersService
#Autowired private lateinit var someUserService : someUserService
#Autowired private lateinit var userController: UsersController
#MockBean private lateinit var userPrincipal: UserPrincipal
#Autowired private lateinit var context: WebApplicationContext
#BeforeEach
fun init(){
dependency = Dependency()
userRepository = UserRepository(db)
userRepository.insert(validUser)
usersService = UsersService(userRepository,dependency,"var")
someUserService = SomeUserService(usersService)
userController = UsersController(usersService,someUserService,dependency)
userPrincipal = UserPrincipal(validUser, null)
this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build()
}
#AfterEach
open fun cleanup() {
SecurityContextHolder.clearContext()
}
#Test
#WithUserDetails("admin",serviceBeanName = "userService", setupBefore = TestExecutionEvent.TEST_EXECUTION)
fun getUsers() {
val result = mockMvc.perform(
MockMvcRequestBuilders.get("/users/",{false}).accept(MediaType.APPLICATION_JSON).contentType(
MediaType.APPLICATION_JSON
)
).andExpect(MockMvcResultMatchers.status().isOk)
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andReturn()
}
Controller:
#RestController
#Validated
#CrossOrigin(origins = ["*"])
#RequestMapping("${API_ROOT}users/")
open class UsersController #Autowired constructor(
private val usersService: UsersService,
private val someService: SomeService,
private val dependency: dependency,
) {
companion object {
fun validatePermissions(principal: UserPrincipal, userId: UserId) {
if (principal.user.id != userId &&
...
}
#GetMapping
#RolesAllowed(ROLE_ADMIN)
fun getAllUsers(
#AuthenticationPrincipal principal: UserPrincipal,
#RequestParam(value = "admin", required = false) includeAdmin: Boolean = false,
#RequestParam(value = "guest", required = false) includeGuest: Boolean = false,
): List<User> {
validatePermissions()
return usersService.getAll()
}
I'm using #Bean and #Autowired
#Component
class ConfigurationServiceInvoker() {
fun getRules(request: RulesRequest): RulesResponse {
return runBlocking { stub.geRules(request) }
}
}
#Component
object InvokerConfiguration {
#Bean
fun getConfigurationServiceInvoker(): ConfigurationServiceInvoker {
return ConfigurationServiceInvoker()
}
}
When I calling getRules() function I got error "lateinit property configurationServiceInvoker has not been initialized", how to fix this issue?
#Autowired
private lateinit var configurationServiceInvoker: ConfigurationServiceInvoker
val response = configurationServiceInvoker.getRules()
configurationServiceInvoker.getRules() is being invoked during construction of the object. Runtime annotation processors like that which handles #Autowired occur after the object is constructed. Consider using #PostConstruct to initialize the response value, like so:
#Autowired
private lateinit var configurationServiceInvoker: ConfigurationServiceInvoker
lateinit var response;
#PostConstruct
fun postConstruct() {
response = configurationServiceInvoker.getRules()
}
For retrieving UserDetails object in spring security protected REST api with #AuthenticationPrincipal annotation, I add a customized filter in the MockMvc object, something likes:
#ExtendWith(SpringExtension::class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class BaseSpringIntegrationTest {
#Autowired
private lateinit var context: WebApplicationContext
lateinit var mockMvc: MockMvc
val mockUser = UsernamePasswordAuthenticationToken(MyUserDetails("MOCK_USER"), "MOCK_PASSWORD", listOf(SimpleGrantedAuthority("MOCKED_ROLE")))
#PostConstruct
fun init() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply<DefaultMockMvcBuilder>(springSecurity(mockSpringSecurityFilter))
.build()
}
private val mockSpringSecurityFilter = object: Filter {
override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {
with ((req as HttpServletRequest).userPrincipal) {
if (this != null)
SecurityContextHolder.getContext().authentication = this as Authentication
}
chain.doFilter(req, res)
}
override fun destroy() {
SecurityContextHolder.clearContext()
}
}
}
And then, I try to call the mockMvc object twice in the some test as follows:
class DummyTests: BaseSpringIntegrationTest() {
#Test
fun dummyTest() {
mockMvc.perform(MockMvcRequestBuilders.post("<MY_URL>").principal(mockUser))
.andExpect(MockMvcResultMatchers.status().`is`(HttpStatus.OK.value()))
mockMvc.perform(MockMvcRequestBuilders.post("<ANOTHER_URL>").principal(mockUser))
.andExpect(MockMvcResultMatchers.status().`is`(HttpStatus.OK.value()))
}
}
When running the test, the java.IllegalStateException is thrown for the second perform likes:
Method not found: BaseSpringIntegrationTest$mockSpringSecurityFilter$1.getFilters(org.springframework.mock.web.MockHttpServletRequest)
java.lang.IllegalStateException: Method not found: BaseSpringIntegrationTest$mockSpringSecurityFilter$1.getFilters(org.springframework.mock.web.MockHttpServletRequest)
at org.springframework.util.ReflectionUtils.handleReflectionException(ReflectionUtils.java:104)
at org.springframework.test.util.ReflectionTestUtils.invokeMethod(ReflectionTestUtils.java:502)
at org.springframework.test.util.ReflectionTestUtils.invokeMethod(ReflectionTestUtils.java:427)
at org.springframework.security.test.web.support.WebTestUtils.findFilter(WebTestUtils.java:121)
at org.springframework.security.test.web.support.WebTestUtils.getSecurityContextRepository(WebTestUtils.java:63)
at org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors$SecurityContextRequestPostProcessorSupport.save(SecurityMockMvcRequestPostProcessors.java:725)
at org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors$TestSecurityContextHolderPostProcessor.postProcessRequest(SecurityMockMvcRequestPostProcessors.java:805)
at org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder.postProcessRequest(MockHttpServletRequestBuilder.java:831)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:173)
And if there is only one perform call in a test, everything works properly.
Could anybody help to handle the problem please.
I had the same problem, I solved it by adding the following method to my MockSpringSecurityFilter
public void getFilters(MockHttpServletRequest mockHttpServletRequest){}
I am studying Kotlin with Spring Boot, and I am trying to use Serenity just for report.
But I have some problem with Mockito because I cannot mock the last part of my code.
That's my case:
#RestController
#RequestMapping("/person")
class PersonController {
#Autowired
private lateinit var personUseCase : PersonUseCase
#GetMapping("/all")
fun findAllPeople(): DataModelResponse<List<PersonDataModelResponse>> {
return DataModelResponse(
PersonDataModelResponseMapper.transform(personUseCase.findAll()))
}
}
#Component
class PersonUseCase {
fun findAll(): List<PersonEntity> {
val personImpl : Person = PersonImplementation()
return personImpl.findAll()
}
}
class PersonImplementation : Person {
private val personDaoResponse : PersonDaoResponse = PersonDaoResponse()
override fun findAll(): List<PersonEntity> {
val listPeopleDao = personDaoResponse.findAll()
return PersonDaoMapper.transform(listPeopleDao)
}
}
internal class PersonDaoResponse (
val identification: Long = 0,
val personName: String = "") {
fun findAll(): List<PersonDaoResponse> {
return listOf(PersonDaoResponse(1, "José"))
}
}
And I am trying to mock my Dao in an integration test:
#RunWith(SerenityRunner::class)
#WithTag("Integration")
#AutoConfigureMockMvc
#WebMvcTest
class PersonControllerTest {
#InjectMocks
private lateinit var personController : PersonController
#InjectMocks
private lateinit var personImplementation : PersonImplementation
#SpyBean
private lateinit var personUseCase : PersonUseCase
#Spy
private val personDaoResponse = PersonDaoResponse()
#Autowired
private lateinit var webApplicationContext: WebApplicationContext
#Autowired
private lateinit var mockMvc: MockMvc
#Rule #JvmField
var springMethodIntegration = SpringIntegrationMethodRule()
#Before
fun init() {
MockitoAnnotations.initMocks(this)
reset(personDaoResponse)
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build()
this.mockMvc = MockMvcBuilders.standaloneSetup(personController).setMessageConverters(MappingJackson2HttpMessageConverter()).build()
}
#Test
fun `integration success`() {
doReturn(listOf(PersonDaoResponse(999L, "Zé")))
.`when`(this.personDaoResponse).findAll()
val result = this.personController.findAllPeople()
assertNotNull(result)
assertEquals(999L, result.data[0].personId)
assertEquals("Zé", result.data[0].name)
}
}
I know this mock is working if I do something I try call the mock method:
assertEquals(999L, this.personDaoResponse.findAll()[0].identification)
How can I Mock this Dao in an integration test like this?
Unfortunately, I don't have an answer for the Mockito problem because I've been off Mockito for way to long.
If Mockito is not a must, I recommend using MockK (https://github.com/mockk/mockk) from my Spring Boot + Kotlin experience. If you need injectable mocked Beans as well, you can add SpringMockK (https://github.com/Ninja-Squad/springmockk) as well.
As your "PersonDaoResponse" is constructed within the PersonImplementation class, you could use something like this with MockK:
every { anyConstructed<PersonDaoResponse>().findAll() } returns listOf(PersonDaoResponse(999L, "Zé"))
Hi I have a test class named UserServiceTest which contains userService class which is injected with the above mocks and the tests in this test class works fine.
#RunWith(MockitoJUnitRunner::class)
class UserServiceTest {
lateinit var login: Login
#Mock
lateinit var userRepository: UserRepository
#Mock
lateinit var emailService: EmailService
#InjectMocks
lateinit var userService: UserService
#Before
fun setup() {
login = Login(email = "mohanraj#gmail.com", password = "qwerty"
}
And I have another test class named AdminServiceTests which contains the AdminServiceClass which is injected with the above mocks which also consists the userService class
#RunWith(MockitoJUnitRunner::class)
class AdminServiceTests {
lateinit var user: User
#Mock
lateinit var userRepository: UserRepository
#Mock
lateinit var adminRepository: AdminRepository
#Mock
lateinit var userService: UserService
#InjectMocks
lateinit var adminService: AdminService
#Before
fun setup() {
this.createAdmin = CreateAdmin().apply {
email = "admin#gmail.com"
name = "admin"
password = "qwerty"
phone = 98345678899
}
}
#Test
fun testCreateAdmin() {
val result = adminService.createAdmin(createAdmin)
Assert.assertEquals(true, result)
}
When I run the test, adminService.createAdmin(createAdmin) calls a function in the adminService which calls a function in userService
fun createAdmin(newUser: CreateAdmin): Boolean {
val user = userService.getUser(newUser)
if (userService.createUser(user)) { // calls a function in user service
this.saveAdmin(user.id)
return true
}
return false
}
I want to call a function in userService from testCreateAdmin function, but the user service which I have included as #Mock contains some dependencies for itself and it is a dependency for adminService, so when I debug the #Mock userService object contains null and so the function in userService is not called. so how to inject the dependencies to userService and inject it into adminService.. Please help
userService = {UserService$MockitoMock$825690330#2479}
mockitoInterceptor = {MockMethodInterceptor#2532}
userRepository = null
emailService = null
In your testCreateAdmin() you have to mock the behavior of the userService methods. By default, non-mocked methods will return null.
It should look like this, with mockito-kotlin.
#Test
fun testCreateAdmin() {
val admin = mock<User>() {
on { id } doReturn "id"
}
whenever(userService.getUser(createAdmin)).doReturn(admin)
whenever(userService.createUser(admin)).doReturn(true)
val result = adminService.createAdmin(createAdmin)
Assert.assertEquals(true, result)
verify(userService).saveAdmin("id")
}