Kotlin junit MockK runner - kotlin

I'm trying to write unit tests using Kotlin and MockK framework. If tests are written using junit 5 framework it's possible to run them using MockKExtension.
#ExtendWith(MockKExtension::class)
But for junit 4 tests is there a MockK runner?
Like:
#RunWith(....)
Without such runner it's required to initialize mocks manually.
private val a: A = mockK()
Is it possible to initialize kotlin mocks using annotation with junit 4?
#MockK
private lateinit var a: A

Quick answer is no.
BUT. It's very simple to use MockK with JUnit 4:
All you need is code like this:
class CarTest {
#MockK
lateinit var car1: Car
#Before
fun setUp() = MockKAnnotations.init(this, relaxUnitFun = true) // turn relaxUnitFun on for all mocks
// And so on…
BTW, it's not hand-crafted example, it's from official documentation

Related

How to mock internal val variableName:Interface=Class using mockk in Kotlin

I am using one val like internal val variableName:Interface=Class when I am writing the unit test for the class I am mocking the variable using mockk. While running the test getting the below error
Code
#VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal val vehicleName: IVehicleNames = VehicleNameManager
Test Code
#RelaxedMockK
private lateinit var vehicleName: IVehicleNames
java.lang.ExceptionInInitializerError
Can any one tell me how I call resolve this problem
I already tried mockkobject

import a test interface from a library's tests into application's tests

I made a library. OrderedCollections. I import and use in an application. In the library is a junit5 test interface. I want to use the test interface in the application.
example, in library you have
interface BinaryTree<K:Comparable<K>,V> : Collection<Pair<K,V> {...}
in The tests for this library you have
interface TreeTests<K : Comparable<K>, V> {
val tree: BinaryTree<K, V>
#Test
fun sorted() {
val list = tree.toList().sortedBy { it.first }
assertIterableEquals(list, tree)
}
}
I made an implementation in the application of BinaryTree, but it is backed by sqlite. I want to use the test interface from the library on the implementation in the application. Like this
class TreeDB:BinaryTree<Int,String>(){...}
In the tests in the application
class TreeDBTests:TreeTests<Int,String> {
override val tree = TreeDB()
}
And then all the tests written for a possible implemention of BinaryTree are run on the TreeDB class.
However, code written in the tests of a library are not exported to consumers of the library. Anyway to make this work?
I recommend to treat test utils as just any other library that serves a purpose. If, as it seems to be in your case, those test utils are also required for testing the original lib, you will have to separate interface and implementation from the original lib, e.g.
bintree-interface <– bintree-testutils (TreeTests etc.)
^– bintree-implementation
Now the tests for bintree-implementation can use TreeTests and your tests for TreeDB can as well.

Why does Mockito throw an "InvalidUseOfMatchersException" at for this code?

I am writing a test for a Spring-Boot project written in Kotlin 1.5. This piece of code does fail at test runtime with an InvalidUseOfMatchersException and I struggle to figure out why:
#SpringBootTest
#AutoConfigureMockMvc
internal class ControllerTest {
#Autowired
lateinit var mockMvc: MockMvc
#MockBean
lateinit var mockedAuthFilter: AuthFilter
#BeforeEach
fun setup() {
assertNotNull(mockedAuthFilter)
`when`(
mockedAuthFilter.shouldProceed(
any(HttpServletRequest::class.java),
any(AuthConfig::class.java)
)
).thenReturn(true)
}
#Test
fun `This call should return without an error`() {
mockMvc.perform(get("/api/entities")).andDo(print()).andExpect(status().isOk)
}
}
All I can find in the web for this error is that you tried an argument matcher on a basic type - but that is not the case here. Have you faced this problem and how did you solve it?
From my understanding the failure comes from a masked nullpointer exception caused by the shouldProceed method itself which doesn't allow a call with nulled arguments, which kind of happens internally in Mockito during the setup of the mocked instance after any() returns.
The solution was to not use Mockito with Kotlin, but the MockK test utility instead.

Kotlintest extensions providing information back to the test

JUnit 5 has a neat extensions functionality which is not compatible with kotlintest even if it runs on JUnit framework. While the simple use cases in which we just need to log something can be handled by the TestListener, we cannot handle more advanced cases. In particular, how to interact with the extension? Ideally, I would like to get a hold of the extension so I could query it.
In JUnit5 it would be (one of the options anyway)
#ExtendWith(MyExtension.class)
class Something() {
#MyAnnotation
MyType myType;
#Test
void doSomething() {
myType.doSomething();
}
}
In JUnit4 it would be even simpler
#Rule
MyRule myRule;
#Test
void fun() {
myRule.something();
}
Of course, there is a SpringExtension but it does the reflective instantiation of the class.
Is there any way to do it easier?
You can keep a reference to an extension/listener before passing it to the overriden function.
For example:
val myListener = MyKotlinTestListener()
val myOtherListener = MyOtherKotlinTestListener()
override fun listeners() = listOf(myListener, myOtherListener)
This way you can do what you want in your tests with that reference available
test("MyTest") {
myListener.executeX()
}
The same goes if you're using an extension of any sort.
They'll still be executed as part of KotlinTest's lifecycle!

How to combine JUnit4 #RunWith(Parameterized.class) and JUnit5 #ParameterizedTest

I am trying to combine the concept of a Parameterized runner from JUnit4 with the JUnit5 Parameterized Test. Essentially I want to test two separate functions on the same set of data.
I know I could just add the function as another argument to the parameterized test itself but I am trying to make changing or adding new functions to test easy.
Would I be able to leverage nested test classes to achieve this? I am not sure the best way to approach.
#RunWith(Parameterized::class)
class RomanNumeralTest(val func: (Int) -> String) {
#ParameterizedTest(name = "{index} - Expect [{0}] should return [{1}]")
#MethodSource("testData")
fun `Test roman numeral from integer values`(num: Int, expected: String) =
assertEquals(expected, func(num))
companion object {
#JvmStatic
#Parameterized.Parameters
fun data(): Collection<Array<(Int) -> String>> {
return listOf(
arrayOf({num -> roman(num)}),
arrayOf({num -> num.toRomanNumeral()})
)
}
#JvmStatic
private fun testData() = sequenceOf(
arrayOf(1, "I"),
arrayOf(2, "II"),
arrayOf(3, "III"),
arrayOf(4, "IV"),
arrayOf(5, "V")
).asStream()
}
}
I tried the same but in the end I came to the conclusion that: you can't.
There is no way you can use the JUnit 4 Parameterized test runner using the annotations which came with JUnit 5.
You need to move to JUnit 5 to use the latest features like TestFactory or all the powerful annotations of parameterized tests described here