how to make mockito test case with Constructor injection - kotlin

I want to make junit test case with mockito
there are Classes.
MyProps : the properties data class #Configuration
MyService : my main logic #Service class
MyClient : webClient class #Component
how to test myService result logic with mockito?? and how to make data class(MyProps) simply???
there error is like this :
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : Parameter specified as non-null is null:
#Configuration
#ConfigurationProperties("application.something")
class MyProps {
lateinit var broker: String
lateinit var url: String
}
#Service
class MyService(private val client: MyClient,
private val myProps: MyProps
){
fun getReulst(params: Params): Flux<MyEntity> {
// some logic, and I want check this part result
return client.get(params)
}
}
#Component
class MyClient(val myProps: MyProps) {
private val webClient: WebClient = WebClient.create()
fun get(params: Params): Flux<MyEntity> {
val params = BodyInserters.fromValue(query)
return webClient
.post()
.uri(myProps.broker)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(params)
.retrieve()
.bodyToFlux(MyEntity::class.java)
}
}
here is test code
//----------------
#SpringBootTest(classes = [MyService::class, MyProps::class, MyClient::class])
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyServiceTest {
#MockBean
private lateinit var myProps: MyProps
#MockBean
private lateinit var myClient: MyClient
#InjectMocks
private lateinit var countService: MyService
#BeforeEach
fun mock() {
given(myProps.broker).willReturn("http://url.com")
given(myProps.web).willReturn("something")
given(myClient.get2(query)).willReturn(
Flux.fromIterable(listOf(
MyEntity("2020-03-22", Count(1)),
MyEntity("2020-03-23", Count(2)),
MyEntity("2020-03-24", Count(3)),
MyEntity("2020-03-25", Count(6)),
MyEntity("2020-03-26", Count(5)),
MyEntity("2020-03-27", Count(4))
))
)
MockitoAnnotations.initMocks(this)
}
#Test
fun `I want to check!! here`(){
val param = Params(1,2,3) // some params
myService.getReulst(param).subscribe() // <- here is error maybe param is null... why??
}
}

Since you're injecting mocks into your service you don't really need a full-blown spring boot test. This will make your tests faster.
Furthermore, since you're mocking MyClient, you're not really calling its code. Therefore whatever happens in MyClient can be ignored here. You'll cover it in its own test.
Here's how I'd write this test with JUnit 5 (you'll have to translate it to JUnit 4 if you're still on it):
#ExtendWith(MockitoExtension::class)
class MyServiceTest(
#Mock val myProps: MyProps,
#Mock val myClient: MyClient
) {
// you can use #InjectMocks if you prefer
val countService: MyService = MyService(myProps, myClient)
#BeforeEach
fun mock() {
// you only need these if they're called in MyService
`when`(myProps.broker).thenReturn("http://url.com")
`when`(myProps.web).thenReturn("something")
`when`(myClient.get(Params(1,2,3))).thenReturn(
Flux.fromIterable(listOf(
MyEntity("2020-03-22", Count(1)),
MyEntity("2020-03-23", Count(2)),
MyEntity("2020-03-24", Count(3)),
MyEntity("2020-03-25", Count(6)),
MyEntity("2020-03-26", Count(5)),
MyEntity("2020-03-27", Count(4))
))
)
}
#Test
fun `I want to check!! here`(){
val param = Params(1,2,3)
myService.getReulst(param).subscribe()
}
}

Related

How to return Generic List in FallbackHandler using Kotlin

I am trying to return List with Generic type from handle(context: ExecutionContext?) method of MicroProfile FallbackHandler using Kotlin. But it's throwing exception like " org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException: Invalid #Fallback on getDistanceData(java.lang.String): fallback handler's type java.util.List<? extends java.lang.String> is not the same as method's return type
"
RestClient :
#GET
#Path("/testFallbackUrl")
#Fallback(DistanceServiceFallback::class)
#CircuitBreaker(
requestVolumeThreshold = 4, failureRatio = 0.75, delay = 5000, successThreshold = 3
)
fun getDistanceData(#QueryParam("date") date: String) : List<String>
Handler:
#RegisterForReflection
class DistanceServiceFallback : FallbackHandler<List<String>> {
#field:Default
#field:Inject
lateinit var logger: Logger
override fun handle(context: ExecutionContext?): List<String> {
logger.error("Inside DistanceServiceFallback handler. ")
return listOf("Hello")
}
}
This is because of a difference in type inference when your kotlin code is processed in Java. The return type of getDistanceData is java.util.List<String> and the handler's return type is as mentioned in the exception java.util.List<? extends java.lang.String>.
The return type java.util.List<String> is observed from the CDI interceptor so I am not sure how exactly it is extracted but obviously it is not carrying <? extends E> information.
The handler's type java.util.List<? extends java.lang.String> is on the other hand extracted from kotlin.collections.List which is defined as public interface List<out E> : Collection<E> which I think is correct as <out E> should translate to <? extends E>.
However, there is an easy workaround:
#GET
#Path("/testFallbackUrl")
#Fallback(DistanceServiceFallback::class)
#CircuitBreaker(
requestVolumeThreshold = 4, failureRatio = 0.75, delay = 5000, successThreshold = 3
)
fun getDistanceData(#QueryParam("date") date: String) : MutableList<String> {
return mutableListOf("Default")
}
#RegisterForReflection
class DistanceServiceFallback : FallbackHandler<MutableList<String>> {
#field:Default
#field:Inject
lateinit var logger: Logger
override fun handle(context: ExecutionContext?): MutableList<String> {
logger.error("Inside DistanceServiceFallback handler. ")
return mutableListOf("Hello")
}
}
which works because MutableList is defined as public interface MutableList<E> : List<E>, MutableCollection<E> and thus it has now an exact generic type.

How to mock an SQLiteOpenHelper

I am trying to mock an SQLiteOpenHelper class in instrumented tests so whenever any fragment tries to get information from the database it returns a generic result. However, I keep getting an error saying:
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class
com.example.cleaningschedule.helpers.DatabaseHandler Mockito cannot
mock/spy because :
final class
at com.example.cleaningschedule.ToDoListInstrumentedTest.oneTask(ToDoListInstrumentedTest.kt:81)
The test class is:
#RunWith(AndroidJUnit4::class)
class ToDoListInstrumentedTest {
#Rule
#JvmField var activityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
private fun getActivity() = activityRule.activity
#After
fun tearDown() {
InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase("TaskDatabase")
}
#Test
fun oneTask() {
val mock = mock(DatabaseHandler::class.java)
`when`(mock.getTasks()).thenThrow()
onView(withId(R.id.taskName)).check(matches(isDisplayed()))
}
}
The class I am trying to mock is:
class DatabaseHandler(context: Context): SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
companion object {
private const val DATABASE_VERSION = 5
private const val DATABASE_NAME = "TaskDatabase"
...
}
override fun onCreate(db: SQLiteDatabase?) {
...
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
...
}
fun getTasks(): MutableList<Pair<MutableList<String>, MutableList<Room>>> {
...
}
}
I have looked at several other similar questions but none have helped:
Error mocking Class which hold reference to SQLiteOpenHelper
Mock final class in java using mockito library - I had a lot of issues with import PowerMock
How to mock a final class with mockito - I have added the dependency and created the file with the mock-maker-inline line as suggested in the answers put I still get the same error. I also tried the answer that suggested Mockito.mock(SomeMockableType.class,AdditionalAnswers.delegatesTo(someInstanceThatIsNotMockableOrSpyable)) but this gave me a 'Not enough information to infer type variable T' error
Mock final class with Mockito 2
Mockito cannot mock/spy because : Final Class
Cannot mock/spy class java.util.Optional
I will made an Interface :
public interface ContainerHandler {
MutableList<Pair<MutableList<String>, MutableList<Room>>> getTasks();
}
Then I made DatabaseHandler inherit this interface, I call Mockito's mock function with the Interface.
val mock = mock(ContainerHandler::class.java)
`when`(mock.getTasks()).thenThrow()
And finally I inject my mock into the tested class.

How do I use TestPropertyProvider and inject RxHttpClient with Micronaut using Kotlin

Note - I'm a Java+Spring guy trying out Kotlin+Micronaut.
I'm trying to use the TestPropertyProvider to set properties after my embedded service starts.
It works ok, as long as there are no constructor parameters in my test class.
I can add the RxHttpClient as a constructor parameter and it gets injected fine.
But, I'd like to inject the RxHttpClient from Micronaut and also implement TestPropertyProvider.
I tried adding #Inject to the RxHttpClient but get the error This annotation is not applicable to target 'local variable' [because the test body is a lambda passed to the superclass]
Without the #Inject I get the error lateinit property client has not been initialized
My base class has the TestPropertyProvider implementation .
abstract class ZeebeSpecification(body: AbstractStringSpec.() -> Unit): StringSpec(body), TestPropertyProvider {
override fun getProperties(): MutableMap<String, String> {
return mutableMapOf("orchestrator.management.client.brokerContactPoint" to IntegrationTestHarness.instance.getBroker())
}
}
TestPropertyProvider works, but RxHttpClient not injected
#MicronautTest
class ZeebeBroker1Test() : ZeebeSpecification({
#Client("/") lateinit var client: RxHttpClient;
...tests
}) {}
RxHttpClient injected, but TestPropertyProvider not evaluated
#MicronautTest
class ZeebeBroker1Test(#Client("/" val client: RxHttpClient) : ZeebeSpecification({
...tests
}) {}
I removed the base class from the equation and made my test directly implement the TestPropertyProvider but it still fails.
#MicronautTest
class ZeebeBroker1Test(#Client("/") var client: HttpClient) : BehaviorSpec(), TestPropertyProvider {
init {
...tests
}
private fun getBroker(): String {
return IntegrationTestHarness.instance.getBroker()
}
override fun getProperties(): MutableMap<String, String> {
return mutableMapOf("orchestrator.management.client.brokerContactPoint" to getBroker())
}
}
Seems like it's the same issue as this, but I'm already using v1.1.2
https://github.com/micronaut-projects/micronaut-test/issues/82
If I tried to use #Inject #Client("/") client: RxHttpClient it would throw the error message: Missing bean argument [LoadBalancer loadBalancer] for type: io.micronaut.http.client.DefaultHttpClient. Required arguments: LoadBalancer
How do I use both TestPropertyProvider and injected RxHttpClient?
I resolved the issue by moving the body of the spec into the init, and injecting the RxHttpClient as a field.
#MicronautTest
class ZeebeBroker1Test() : ZeebeSpecification() {
#Inject #field:Client("/") lateinit var client: RxHttpClient
private val log: Logger = LoggerFactory.getLogger(ZeebeBroker1Test::class.java)
init {
"test case 1" {
...
}
"test case 2" {
...
}
}
}
And I let the base class implement the TestPropertyProvider interface .
abstract class ZeebeSpecification(): StringSpec(), TestPropertyProvider {
open fun getBroker(): String {
return IntegrationTestHarness.instance.getBroker()
}
override fun getProperties(): MutableMap<String, String> {
return mutableMapOf("orchestrator.management.client.brokerContactPoint" to getBroker())
}
}

Mocking a queue in Kotlin with Mockito does not seem to work

I have a simple named service which uses a queue:
#Named
class OrderFormService #Inject constructor(
private val repository: OrderFormRepository
) {
private val queue: Queue<OrderForm> = LinkedList()
private val logger: Logger = LoggerFactory.getLogger("service")
fun getNextOrderForm(input: GetNextOrderFormInput): GetNextOrderFormPayload? {
if (queue.isEmpty()) {
logger.info("queue is empty")
val forms: List<OrderForm> = repository.findTop1000ByImageTypeAndImageState(input.type, input.state)
forms.forEach {
queue.offer(it)
}
}
if (!queue.isEmpty()) {
return GetNextOrderFormPayload(queue.poll())
}
return null
}
}
While trying to unit test this I want to mock the queue:
#ExtendWith(MockitoExtension::class)
internal class OrderFormServiceTest {
#Mock
private val queue: Queue<OrderForm> = LinkedList()
#Mock
lateinit var repository: OrderFormRepository
#InjectMocks
lateinit var service: OrderFormService
#Test
fun givenValidInputAndFilledQueueWhenGetNextOrderFormThenReturnPayload() {
// given
val expected = createOrderForm()
val expectedPayload = GetNextOrderFormPayload(expected)
given(queue.isEmpty()).willReturn(false)
given(queue.poll()).willReturn(expected)
// when
val input = GetNextOrderFormInput(ImageType.NUMBER, ImageState.UNCLASSIFIED)
val result = service.getNextOrderForm(input)
// then
assertThat(result).isEqualTo(expectedPayload)
}
}
But the queue is always empty. So I guess the queue is not getting mocked correctly. What am I doing wrong?
EDIT
Things I have tried:
Making queue not final:
...
var queue: Queue<OrderForm> = LinkedList()
...
Using Mockito.mock:
...
var queue = Mockito.mock(Queue::class.java)
`when`(queue.isEmpty()).thenReturn(false)
`when`(queue.poll()).thenReturn(expected)
...
Your queue is not marked as #Autowired or part of the constructor, thus Mockito cannot mock it.
In order to make this work (haven't verified it though), define your constructor like this:
#Named
class OrderFormService #Inject constructor(
private val repository: OrderFormRepository,
private val queue: Queue<OrderForm>
) { }
Now, in order to have the queue initialized in your regular program, you have to define a bean for it, something like:
#Configuration
class QueueConfiguration {
#Bean
fun queue() : Queue<OrderForm> = LinkedList()
}
Furthermore, you should keep in concern that #InjectMocks only will use one injection method. So you can't mix constructor initialisation with property setters or field injection.
Also have a look at #MockBean. This replaces the bean globally and can be more convenient to use. It has the drawback that it dirties the context, resulting in context reinitialization and potentially slower tests if they aren't sliced properly.
EDIT:
Another alternative would be to set the mock manually (samples not verified, hope they work work you). I recommend using https://github.com/nhaarman/mockito-kotlin to make the Mockito syntax more kotlinish.
Setting the mock manually requires to make the queue a publicly settable property:
#Named
class OrderFormService #Inject constructor(
private val repository: OrderFormRepository
) {
var queue: Queue<OrderForm> = LinkedList()
}
Then, you assign the mock in your test:
internal class OrderFormServiceTest {
private val queue: Queue<OrderForm> = mock {}
#Mock
lateinit var repository: OrderFormRepository
#InjectMocks
lateinit var service: OrderFormService
#BeforeEach
fun setup() {
service.queue = queue
}
}
There's one issue with this though: depending on the framework you use, your OrderFormService might be initialised only once. When setting the queue, you change the global object which might affect other tests. To mitigate this, #DirtiesContext on your test will ensure that the whole context is rebuilt (which impacts test performance). This is more or less the same which #MockBean would do for you (with the same performance impact). You can also clean the object yourself though.

How to use MicronautTest with Kotlintest to inject beans while testing ? in Kotlin

How to inject the following into Test, as no constructor args are allowed
and its failed to initialise the injected beans
#MicronautTest
class ApplicationTest:StringSpec() {
#Inject
lateinit val embeddedServer:EmbeddedServer;
#Inject
lateinit val dataSource:DataSource
init{
"test something"{
//arrange act assert
}
}
}
You need to specify Project config by creating an object that is derived from AbstractProjectConfig, name this object ProjectConfig and place it in a package called io.kotlintest.provided. KotlinTest will detect it's presence and use any configuration defined there when executing tests.
as per the documentation
https://github.com/kotlintest/kotlintest/blob/master/doc/reference.md#project-config
object ProjectConfig :AbstractProjectConfig() {
override fun listeners() = listOf(MicornautKotlinTestExtension)
override fun extensions() = listOf(MicornautKotlinTestExtension)
}
Because the test cases are passed like a lambda to the parent class constructor, you have to use constructor injection
#MicronautTest
class ApplicationTest(
private val embeddedServer: EmbeddedServer,
private val dataSource: DataSource
): StringSpec({
"test something"{
//arrange act assert
}
})
You can look at any of the tests in the project for a running example. https://github.com/micronaut-projects/micronaut-test/blob/master/test-kotlintest/src/test/kotlin
Have you tried to write your code like this ?
#MicronautTest
class ApplicationTest:StringSpec() {
val embeddedServer:EmbeddedServer
val dataSource:DataSource
#Inject
ApplicationTest(embeddedServer:EmbeddedServer, dataSource:DataSource) {
this.embeddedServer = embeddedServer
this.dataSource = dataSource
}
init{
"test something"{
//arrange act assert
}
}
}
This should work.