How to mock internal val variableName:Interface=Class using mockk in Kotlin - 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

Related

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.

Dagger Dependency Injection in main function

I am calling a function in a class S3FileOperationsAdapter from the main function in my kotlin code. I am injecting the class S3FileOperationsAdapter in the main function file. So it looks like
class Runner {
#set:Inject
lateinit var s3FileOperationsAdapter: S3FileOperationsAdapter
fun main(args: Array<String>) {
s3FileOperationsAdapter.readFunction()
}
}
Now the issue is:
When I try to run the above code, I get the error Error: Main method is not static in class com.amazon.bram.sim.BatchJobRunner, please define the main method as:. This is understandable.
And we can only make a static function within an object in kotlin. So upon doing that, I cannot Inject the dependency, because Dagger does not support injection into Kotlin objects. So it feels like a deadlock.
My question is, I want to inject the dependency in this file anyhow so that I can call the respective function. And I am calling this function from the "fun main()" in kotlin. How can I achieve this? Has anyone ever faced this before?
In order to inject anything in Dagger, you must first create an instance of your component. Since no code at all will run before fun main(), this needs to be done during main itself (or in a field initializer).
After creating an instance of the component, you can ask it for an instance of S3FileOperationsAdapter directly.
fun main(args: Array<String>) {
// Create the component.
val component = DaggerMyComponent.create()
// or use the Component.Builder or Component.Factory you defined for MyComponent.
// Get an object from the component.
// This method should be defined in your component interface.
val adapter = component.s3FileOperationsAdapter()
// Use the object.
adapter.readFunction()
}
If your actual code is more complicated, with multiple injected objects and a longer main() function, this may be a bit unwieldy. In that case, you can extract your current main() into its own class and let Dagger provide that class in main().

Testcontainers: execute TC_INITSCRIPT at each test

In a quakus project, I successfully set up testcontainers using only the following configuration:
%test.quarkus.datasource.driver=org.testcontainers.jdbc.ContainerDatabaseDriver
%test.quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL9Dialect
%test.quarkus.datasource.url=jdbc:tc:postgresql:11:///dbname?TC_INITSCRIPT=file:my-file.sql
This is amazing how easy it is.
However, as I test the deletion of entities, I'd like to execute the initscript before each test, i.a. start each test with the initial DB.
Any idea how to achieve it?
I also tested by creating the PostgreSQLContainer from the test class in order to manage its lifecycle as I need. The problem is that the container port value is random, I need to set it in quarkus configuration but it doesn't work (it seems to be too late: "Connection to 127.0.0.1:6432 refused"). I did it this way:
#Testcontainers
#QuarkusTest
class MyTest {
class MyPostgreSQLContainer(imageName: String) : PostgreSQLContainer<MyPostgreSQLContainer>(imageName)
companion object {
#Container
val postgres = MyPostgreSQLContainer("postgres:11")
.withDatabaseName("integtest")
.withUsername("postgres")
.withPassword("pwd")
.withExposedPorts(5432)
#BeforeAll
#JvmStatic
internal fun beforeAll() {
postgres.start()
System.setProperty("QUARKUS_DATASOURCE_JDBC_URL", "jdbc:postgresql://127.0.0.1:${postgres.firstMappedPort}/kpi_integtest");
println("BeforeAll init() method called")
}
}
with the application.properties config:
quarkus.datasource.jdbc.url=jdbc:postgresql://127.0.0.1:6432/integtest

Receiving NoClassDefFoundError when invoking generated serializer() method

I’m getting a NoClassDefFoundError when trying to invoke the Foo.serializer() method on a #Serializable class.
Here's my test case:
#Serializable
data class Foo(val data: String)
val jsonString = json.stringify(
Foo.serializer(), // <= Error happens here
Foo(data = "foo")
)
Attempting to run the code results in the following stack trace:
java.lang.NoSuchMethodError: 'void kotlinx.serialization.internal.SerialClassDescImpl.<init>(java.lang.String, kotlinx.serialization.internal.GeneratedSerializer, int)'
at com.example.Foo$$serializer.<clinit>(Foo.kt:7)
at com.example.Foo$Companion.serializer(Foo.kt)
This is the result of version mismatches between Kotlin and Kotlinx.serialization, as they are relatively tightly coupled. In my case I was using Kotlin 1.3.71 and kotlinx.serialization 0.14.0, so the solution was to upgrade kotlinx.serialization to 0.20.0.

Kotlin junit MockK runner

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