Reputation: 1524
So I have a class
class Test<T : SomeListener> @Inject constructor(
private val dependency1: Dependency1,
private val listener: T
)
I'm trying to write a unit test for it using mockk and running into an error when trying to mock and initialize it with the generic type.
class TestTest {
@MockK
lateinit var dependency1: Dependency1
@MockK
lateinit var listener: ListenerImpl
@InjectMockKs(overrideValues = true)
lateinit var testObject: Test<ListenerImpl>
}
I keep getting an error "io.mockk.MockKException: No matching constructors found: ... listener : T =
What is the right way to get it to mock the constructor correctly with this generic parameter value?
Upvotes: 2
Views: 2213
Reputation: 79
I uses something like below in a SpringBoot context, injecting the parameters should work:
@ExtendWith(MockKExtension::class)
class SomeTestTest(
@MockK private val mockDependency1: Dependancy1,
@MockK private val mockListener: ListenerImpl
) {
@InjectMockKs
lateinit var testObject: SomeTest<Listener>
@Test
fun test() {
every { mockDependency1.test() } returns "test"
every { mockListener.listen(any()) } returns Unit
testObject.test()
verify { mockListener.listen("test") }
}
}
@Service
class SomeTest<Listener>
(
private val dependancy1: Dependancy1,
private val listener: ListenerImpl
)
{
fun test(): String {
val s = dependancy1.test()
listener.listen(s)
return s
}
}
interface Listener {
fun listen(s: String): Unit
}
@Service
class Dependancy1 {
fun test() = "test"
}
@Component
class ListenerImpl: Listener {
override fun listen(s: String): Unit {
println(s)
}
}
Upvotes: 0
Reputation: 857
You can do this by instantiating the service/class that you wish to test upon setup and pass the mocks as paramters. This is an alternative approach to using annotations like @MockK
and @InjectMocks
. Here is how you would do it:
import io.mockk.mockk
import io.quarkus.test.junit.QuarkusTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.BeforeEach
@QuarkusTest
class TestTest {
// Instantiate the dependency mocks to be able to pass them as parameters
private val dependency1 = mockk<Dependency1>(relaxed = true)
private val listener = mockk<ListenerImpl>(relaxed = true)
@BeforeEach
fun setup() {
// Instantiate the class under test, and pass the mocks from above
testObject = Test<ListenerImpl>(depencency1, listener)
}
// Write your tests here
@Test
fun firstMethodTest() {
// Setup
// ...
// When you want to call the testObject, simply do
testObject.firstMethod()
}
}
Note: the (relaxed = true) parameter is optional, it simply provides a default value for any method that you haven't provided a mock return value for.
Upvotes: 0
Reputation: 1524
Unfortunately I wasn't able to figure out a way to purely do it with annotations. What I ended up doing was:
class TestTest {
@MockK
lateinit var dependency1: Dependency1
@MockK
lateinit var listener: ListenerImpl
lateinit var testObject: Test<SomeListener>
@BeforeEach
fun setUp() {
testObject = Test(
dependency1,
listener
)
}
}
This worked and initialized the testObject correctly.
Upvotes: 0