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()
}
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 have following class (partial code):
#Component
class TestClass: InitializingBean, DisposableBean {
#Autowired
private lateinit var testBean: SomeObject
override fun afterPropertiesSet(){
log.info("testBean 1: $testBdean")
}
fun testFunction(testName: String): Boolean {
log.info("testBean 2: $testBdean")
}
#Throws(Exception::class)
override fun destroy() {
}
}
I saw testBean 1 was run successfully but testBean 2 gave error: lateinit property testBean has not been initialized. So the testBean bean was initialized in afterPropertiesSet() and not available in other functions? I know if we put testBean in the constructor TestClass(testBean) it will be initialized and available to all functions. But is there another way because TestClass will be called from other packages and not every package can pass the testBean to the constructor.
You could create an object that holds your TestClass and use that holder to refer to your create component
something like:
#SpringBootApplication
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
#Component
class SomeObject(val name:String = "some object")
#Component
class TestClass(val someObject: SomeObject) {
init {
TestClassHolder.testClass = this
}
fun test() = someObject.name
}
object TestClassHolder {
lateinit var testClass: TestClass
}
class NotBeanClass {
fun call() = TestClassHolder.testClass.test()
}
#RestController
class TestController {
#GetMapping
fun test() = NotBeanClass().call()
}
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é"))
I'm using MongoDB and Spring over Kotlin and i want my application to populate a MongoDB collection upon startup. (and clean it every time it starts)
My question is, how can i populate the data one by one in order to be fault tolerant in case some of the data I'm populating with is problematic?
my code:
#Configuration
class IndicatorPopulator {
#Value("classpath:indicatorData.json")
private lateinit var data: Resource
#Autowired
private lateinit var indicatorRepository: IndicatorRepository
#Bean
#Autowired
fun repositoryPopulator(objectMapper: ObjectMapper): Jackson2RepositoryPopulatorFactoryBean {
val factory = Jackson2RepositoryPopulatorFactoryBean()
indicatorRepository.deleteAll()
factory.setMapper(objectMapper)
factory.setResources(arrayOf(data))
return factory
}
What I am looking for is something like:
#Bean
#Autowired
fun repositoryPopulator(objectMapper: ObjectMapper): Jackson2RepositoryPopulatorFactoryBean {
val factory = Jackson2RepositoryPopulatorFactoryBean()
indicatorRepository.deleteAll()
factory.setMapper(objectMapper)
val arrayOfResources: Array<Resource> = arrayOf(data)
for (resource in arrayOfResources){
try{
factory.setResources(resource)
} catch(e: Exception){
logger.log(e.message)
}
}
return factory
}
Any idea on how to do something like that would be helpful...
Thanks in advance.
There is no built in support for your ask but you can easily provide by tweaking few classes.
Add Custom Jackson 2 Reader
public class CustomJackson2ResourceReader implements ResourceReader {
private static final Logger logger = LoggerFactory.getLogger(CustomJackson2ResourceReader.class);
private final Jackson2ResourceReader resourceReader = new Jackson2ResourceReader();
#Override
public Object readFrom(Resource resource, ClassLoader classLoader) throws Exception {
Object result;
try {
result = resourceReader.readFrom(resource, classLoader);
} catch(Exception e) {
logger.warn("Can't read from resource", e);
return Collections.EMPTY_LIST;
}
return result;
}
}
Add Custom Jackson 2 Populator
public class CustomJackson2RepositoryPopulatorFactoryBean extends Jackson2RepositoryPopulatorFactoryBean {
#Override
protected ResourceReader getResourceReader() {
return new CustomJackson2ResourceReader();
}
}
Configuration
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public AbstractRepositoryPopulatorFactoryBean repositoryPopulator(ObjectMapper objectMapper, KeyValueRepository keyValueRepository) {
Jackson2RepositoryPopulatorFactoryBean factory = new CustomJackson2RepositoryPopulatorFactoryBean();
keyValueRepository.deleteAll();
factory.setMapper(objectMapper);
factory.setResources(new Resource[]{new ClassPathResource("badclassname.json"), new ClassPathResource("good.json"), new ClassPathResource("malformatted.json")});
return factory;
}
}
I've uploading a working example here
Using Sagar's Reader & Factory I just adjusted it to fit my needs (Kotlin, and reading resources all from the same JSON file) got me this answer:
#Configuration
class IndicatorPopulator {
#Value("classpath:indicatorData.json")
private lateinit var data: Resource
#Autowired
private lateinit var indicatorRepository: IndicatorRepository
#Autowired
#Bean
fun repositoryPopulator(objectMapper: ObjectMapper): Jackson2RepositoryPopulatorFactoryBean {
val factory: Jackson2RepositoryPopulatorFactoryBean = CustomJackson2RepositoryPopulatorFactoryBean()
factory.setMapper(objectMapper)
// inject your Jackson Object Mapper if you need to customize it:
indicatorRepository.deleteAll()
val resources = mutableListOf<Resource>()
val readTree: ArrayNode = objectMapper.readTree(data.inputStream) as ArrayNode
for (node in readTree){
resources.add( InputStreamResource(node.toString().byteInputStream()))
}
factory.setResources(resources.toTypedArray())
return factory
}
}
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")
}