Kotlin spring controller integration test not working - spring

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()
}

Related

lateinit property has not been initialized when using #Autowired

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()
}

Kotlin + Mockito + Spring-boot

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é"))

How to test controller with auth via jwt

I'm new in Spring. I need to know how to test my controller:
#RestController
#RequestMapping("/api/game")
class GameController {
#Autowired
lateinit var userRepository: UserRepository
#Autowired
lateinit var gameRepository: GameRepository
#Autowired
lateinit var gameService: GameService
#PostMapping("/start")
fun start(#CurrentUser currentUser: UserPrincipal): Game {
val user = userRepository.findById(currentUser.id!!).get()
return gameService.createGame(user)
}
}
I use jwt token to auth, and I cannot test my controller without it now. How to do it? How to mock it?

Mock a Service class with dependencies in another Service Class Mockito

I want to Mock a Service class with dependencies in another Service Class Mockito.
UserService Class
#Service
class UserService(
val userRepository: UserRepository,
val userRoleRepository: UserRoleRepository,
val jwtGenerator: JwtGenerator,
val emailService: EmailService
)
AdminService Class
#Service
class AdminService(
val userService: UserService,
val userRepository: UserRepository,
val adminRepository: AdminRepository
)
Now I'm trying to write unit test with these classes as follows
#RunWith(MockitoJUnitRunner::class)
class AdminServiceTests {
private lateinit var createAdmin: CreateAdmin
#Mock
lateinit var userRepository: UserRepository
#Mock
lateinit var userRoleRepository: UserRoleRepository
#Mock
lateinit var jwtGenerator: JwtGenerator
#Mock
lateinit var emailService: EmailService
#InjectMocks
lateinit var userService: UserService
#Mock
lateinit var userRepository: UserRepository // Conflicting declarations
#Mock
lateinit var adminRepository: AdminRepository
#InjectMocks
lateinit var adminService: AdminService
#Before
fun setup() {
this.createAdmin = CreateAdmin().apply {
email = "admin#gmail.com"
name = "admin"
password = "qwerty"
phone = 9873555555555
}
}
#Test
fun testCreateAdmin() {
val result = adminService.createAdmin(createAdmin)
Assert.assertEquals(true, result)
}
}
Please advice how to mock the userService inside AdminService with all the four dependencies injected
You can create object of UserService with its dependencies as mocked objects and then use it as a dependency in AdminServiceTests.
If you're using Gradle & Spring, add this plugin to your build.gradle
plugins {
kotlin("plugin.spring") version "1.3.72"
}
Mockito should then work without having to mock the dependencies of the service:
val userService = Mockito.mock(UserService::class.java)

Call a function from Test class not working Mockito

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")
}

Resources