I would like to check my configuration by using the checkModules() method provided by koin-test as explained here.
However, I am using injection parameters and my test fails with an exception:
org.koin.core.error.NoParameterFoundException: Can't get parameter value #0 from org.koin.core.parameter.DefinitionParameters#3804648a
Here is a simple test to demonstrate the issue:
import org.junit.Test
import org.koin.dsl.koinApplication
import org.koin.dsl.module
import org.koin.test.KoinTest
import org.koin.test.check.checkModules
class TestCase : KoinTest {
#Test
fun checkModules() {
koinApplication {
modules(
module { factory { (msg: String) -> Message(msg) } }
)
}.checkModules()
}
data class Message(val message: String)
}
Is there a way to make this work? How could I provide the missing parameter?
You need to pass this parameter to your test, like this:
class TestCase : KoinTest {
#Test
fun checkModules() {
koinApplication {
modules(module { factory { (msg: String) -> Message(msg) } })
}.checkModules {
create<Message> { parametersOf("testMessage") }
}
}
data class Message(val message: String)
}
Example from Koin repository: CheckModulesTest.kt#L156
My issue with the same question: Issue
Related
I'm trying to build routes for my service with Micronaut. Following this tutorial the example works fine.
This is my controller:
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.PathVariable
#Controller
class DemoController {
#Get
fun issue(
#PathVariable a: String): String {
return "Issue # $a"
}
}
And this is my route class:
import io.micronaut.context.ExecutionHandleLocator
import io.micronaut.web.router.DefaultRouteBuilder
import io.micronaut.web.router.RouteBuilder
import jakarta.inject.Inject
import jakarta.inject.Singleton
#Singleton
class MyRoutes(executionHandleLocator: ExecutionHandleLocator,
uriNamingStrategy: RouteBuilder.UriNamingStrategy) :
DefaultRouteBuilder(executionHandleLocator, uriNamingStrategy) {
#Inject
fun issuesRoutes(demoController: DemoController) {
GET("/issues/show/{number}", demoController, "issue", String::class.java)
}
}
Everything working fine so far.
The problem is that I have more than one parameter in the endpoint. For example:
#Controller
class DemoController {
#Get
fun issue(
#PathVariable a: String,
#PathVariable b: String
): String {
return "Issue # $a"
}
}
In MyRoutes class, on the function issuesRoutes, I need to set the parameterTypes for 2 params now, and I don't know how should I do it.
The documentation of RouteBuilder says as follow:
Route the specified URI template to the specified target.
The number of variables in the template should match the number of method arguments
Params:
uri – The URI
target – The target
method – The method
**parameterTypes – The parameter types for the target method**
Returns:The route
#Override
public UriRoute GET(String uri, Object target, String method, Class... parameterTypes) {
return buildRoute(HttpMethod.GET, uri, target.getClass(), method, parameterTypes);
}
How could I tell the method the types of my two string params (#PathVariables) in this kind of param the method is expecting (Class... parameterTypes).
The error I get with this configuration is:
Caused by: io.micronaut.web.router.exceptions.RoutingException: No such route: com.example.rest.DemoController.issue
Given a controller:
#Controller
class DemoController {
#Get
fun issue(#PathVariable a: String, #PathVariable b: String) = "Issue # a=$a b=$b"
}
The route would be:
#Singleton
class MyRoutes(executionHandleLocator: ExecutionHandleLocator,
uriNamingStrategy: RouteBuilder.UriNamingStrategy) :
DefaultRouteBuilder(executionHandleLocator, uriNamingStrategy) {
#Inject
fun issuesRoutes(demoController: DemoController) {
GET("/issues/show/{a}/{b}", // uri
demoController, // target
"issue", // method
String::class.java, String::class.java) //vararg parameterTypes:Class
}
}
If I were trying to add mocks to the following code (where the MyTypeBuilder is mocked to return a mocked MyType - which implements Closeable):
myTypeBuilder.build(myTypeConfiguration).use { myType ->
myType.callMyMethod()
}
Then trying to verify interactions with myType.callMethod() something like:
myType: MyType = mock()
myTypeBuilder: MyTypeBuilder = mock()
whenever(myTypeBuilder.build(any())).thenReturn(myType)
doMethodCall()
verify(myType, times(1)).callMyMethod()
I'm getting errors:
Wanted but not invoked:
myType.callMethod()
-> at package.me.MyType.callMyMethod(MyType.kt:123)
However, there was exactly 1 interaction with this mock:
myType.close()
-> at kotlin.io.CloseableKt.closeFinally(Closeable.kt:57)
So it appears that I need to add a whenever to execute the use block, but I'm not sure what that should look like. Alternatively, the use should act like a Mockito spy rather than a mock, but then allow mocking on the other methods.
I tried to reconstruct the error by writing the following code which is basically what you wrote in your question plus some println statements and some boilerplate to make it runnable:
import org.junit.jupiter.api.Test
import org.mockito.Mockito.*
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.io.Closeable
open class MyTypeBuilder {
open fun build(config: Any): MyType {
println("build")
return MyType()
}
}
open class MyType : Closeable {
fun callMyMethod() {
println("callMyMethod")
}
override fun close() {
println("close")
}
}
val myTypeConfiguration: Any = "heyho"
fun call(myTypeBuilder: MyTypeBuilder) {
myTypeBuilder.build(myTypeConfiguration).use { myType ->
println("call")
myType.callMyMethod()
}
}
class MockAndUseTest {
#Test
fun test() {
val myType: MyType = mock()
val myTypeBuilder: MyTypeBuilder = mock()
whenever(myTypeBuilder.build(any())).thenReturn(myType)
call(myTypeBuilder)
verify(myType, times(1)).callMyMethod()
}
}
When I run the test case test, it succeeds and is green.
So, unfortunately whatever may cause your problem, it is not contained in the details given by your question.
I'm trying to find a workaround to make a Spring Reactive Webclient work with JDBC.
Here is were I got the idea from: https://gitorko.github.io/2019/04/02/Spring-Webflux-Reactive-JDBC/.
I'm writing a service that calls the jdbc repository interface and instead of returning the type of my domain object MyClass returns a Mono<MyClass> like this:
//other specific imports here
import org.springframework.stereotype.Service
import reactor.core.publisher.Mono
import reactor.core.scheduler.Scheduler
import reactor.core.scheduler.Schedulers
import java.util.concurrent.Callable
#Service
class MyClassService(val repo: MyClassRepository, val jdbcScheduler: Scheduler){
fun save(obj: MyClass?): Mono<MyClass?>? {
return asyncCallable { repo.save(obj) }
}
protected fun <S> asyncCallable(callable: Callable<S>?): Mono<S>? {
return Mono.fromCallable(callable).subscribeOn(Schedulers.parallel()).publishOn(jdbcScheduler)
}
}
//this is a jdbc repository
interface MyClassRepository : CrudRepository<MyClass, UUID> {}
Now the problem is that calling asyncCallable { repo.save(obj) } returns the compile error inferred type is MyClass? but TypeVariable(S) was expected and Mono.fromCallable(callable).subscribeOn(Schedulers.parallel()).publishOn(jdbcScheduler) returns the compile error inferred type is Callable<S>? but Callable<out TypeVariable(T)!> was expected.
I understand by reading about kotlin generics that this has to do with the variance. If I'm not wrong the function asyncCallableis invariant on the generic type Sand in this case covariance is required?
I think the syntax you need is asyncCallable(Callable { repo.save(obj) }).
Complete example:
#Service
class MyClassService(val repo: MyClassRepository, val jdbcScheduler: Scheduler){
fun save(obj: MyClass): Mono<MyClass?>? {
return asyncCallable(Callable { repo.save(obj) })
}
protected fun <S> asyncCallable(callable: Callable<S>): Mono<S>? {
return Mono.fromCallable(callable).subscribeOn(Schedulers.parallel()).publishOn(jdbcScheduler)
}
}
I'd also remove the ?s, but I left them to keep it as close to your code as possible.
For some reason I can't get constructor injection to work with Kodein.
This is the code to reproduce the exception:
import org.kodein.di.Kodein
import org.kodein.di.direct
import org.kodein.di.generic.bind
import org.kodein.di.generic.instance
import org.kodein.di.generic.provider
fun main(args: Array<String>) {
val kodein = Kodein {
bind<Test2>() to provider { Test2() }
bind<Test>() to provider { Test(instance()) }
}
val test = kodein.direct.instance<Test>()
}
class Test(val test2: Test2)
class Test2
The exception:
Exception in thread "main" org.kodein.di.Kodein$NotFoundException: No binding found for bind<Test>() with ? { ? }
Registered in this Kodein container:
at org.kodein.di.internal.KodeinContainerImpl.factory(KodeinContainerImpl.kt:174)
at org.kodein.di.KodeinContainer$DefaultImpls.factory$default(KodeinContainer.kt:33)
at org.kodein.di.KodeinContainer$DefaultImpls.provider(KodeinContainer.kt:80)
at org.kodein.di.internal.KodeinContainerImpl.provider(KodeinContainerImpl.kt:7)
at org.kodein.di.KodeinContainer$DefaultImpls.provider$default(KodeinContainer.kt:79)
at org.kodein.di.internal.DKodeinBaseImpl.Instance(DKodeinImpl.kt:33)
at AppKt.main(App.kt:20)
Why doesn't this work?
bind<Test2>() to provider { Test2() }
^^
This is Kotlin's to function, that generates a Pair, nothing to do with Kodein's DSL :p
Kodein's DSL uses with:
bind<Test2>() with provider { Test2() }
^^^^
Note that, when you are binding a type to itself, you can use a simpler syntax:
bind() from provider { Test2() }
I have an extension function for interface like the following:
import javax.jms.ConnectionFactory
fun ConnectionFactory.foo() {
println("do some stuff")
}
How can I mock the function foo?
Please note, I have seen approaches for classes and objects in http://mockk.io/#extension-functions, but it does not work. I have tried this one:
import io.mockk.classMockk
import io.mockk.every
import org.junit.Test
import javax.jms.ConnectionFactory
class ExtensionFunctionTest {
#Test
fun mockExtensionFunction() {
val connectionFactory = classMockk(ConnectionFactory::class)
every { connectionFactory.foo() } returns println("do other stuff")
connectionFactory.foo()
}
}
It throws exception:
io.mockk.MockKException: Missing calls inside every { ... } block.
According to the documentation in case of module wide extension functions you need to staticMock "hidden" class created for an extension function.
Here is an example (assuming the file name is com/sample/extmockingtest/SampleTest.kt):
fun <T> Iterable<T>.foo(): String = "do some stuff"
class ExtensionFunctionTest {
#Test
fun mockExtensionFunction() {
val itMock = classMockk(Iterable::class);
staticMockk("com.sample.extmockingtest.SampleTestKt").use {
every {
itMock.foo()
} returns "do other stuff"
assertEquals("do other stuff", itMock.foo())
verify {
itMock.foo()
}
}
}
}