How to correct "verify should appear after all code under test has been exercised" when verify is last? - scalamock

I get the error "verify should appear after all code under test has been exercised" with the following:
class CowTest extends MockFactory {
Cow.init(testCowProcesses)
#Test
def noProcessesTest: Unit = {
val cow: Cow = Cow(testCowProcesses)
cow.simulateOneDay(0 nanoseconds)
}
#Test
def processSimulationTest: Unit = {
val NUMBER_OF_TRIES: Int = 10
val cow: Cow = Cow(testCowProcesses)
for (ii <- 0 until NUMBER_OF_TRIES) {
cow.simulateOneDay(0 nanoseconds)
}
(cow.metabolicProcess.simulateOneDay _).verify(0 nanoseconds).repeated(NUMBER_OF_TRIES)
}
}
testCowProcesses is defined in another file, like this (abbreviated):
object CowTesters extends MockFactory {
val metProc = stub[MetabolicProcess]
(metProc.replicate _).when().returns(metProc)
val testCowProcesses = CowProcesses(metProc)
}
I don't quite understand the error message. If I comment out the verify line, the test runs. Alternatively, if I comment out the first test, the second test can run. There are no other tests in the test class. This seems to indicate that the stub objects cannot be reused, as they were in mockito (I'm adapting code from mockito).
Is the best solution to reinstantiate the mock objects, perhaps by converting CowTesters into a class?
Edit:
I confirmed the above suggestion works (not sure if it is the best), but in the mean time I did something a bit more convoluted to get me through compiles:
//TODO: once all tests are converted to ScalaMock,
//TODO: just make this a class with a companion object
trait CowTesters extends MockFactory {
val metProc = stub[MetabolicProcess]
(metProc.replicate _).when().returns(metProc)
val testCowProcesses = CowProcesses(metProc)
}
object CowTesters extends CowTesters {
def apply(): CowTesters = new CowTesters {}
}

From your code above, it seems you are either trying to use JUnit or TestNG. ScalaMock doesn't support either of those frameworks directly, which is why you are struggling with the verification of mocks.
You need to implement your tests using either ScalaTest, or Specs2. See http://scalamock.org/user-guide/integration/
The conversion from JUnit to ScalaTest should be pretty straightforward if you switch to e.g. a FunSuite: http://www.scalatest.org/user_guide/selecting_a_style

Related

Is it possible to disable inlining of value classes in Kotlin?

Goal
I would like to globally disable inlining of #JvmInline value class classes via a compiler flag or something similar. I would want to do this when running unit tests but not in production.
Motivation
I would like to use mockk with value classes.
I want to write a unit test that looks like this:
#JvmInline
value class Example(private val inner: Int)
class ExampleProvider {
fun getExample(): Example = TODO()
}
#Test
fun testMethod() {
val mockExample = mockk<Example>()
val mockProvider = mockk<ExampleProvider> {
every { getExample() } returns mockExample
}
Assert.assertEquals(mockExample, mockProvider.getExample())
}
This code fails with the following exception:
no answer found for: Example(#4).unbox-impl()
I think that if I were able to disable class inlining that this would no longer be an issue.

How does the Mockk library mock a non-interface class?

When I built a structure like the one below, I saw that the classes that are not executed through the interfacecan also be mockable.
How does this work? Could it be related to Kotlin?
In fact, my question here is; How does it crush the function of a class without override? I'm curious about the background of this.
class Sample {
fun returnFive() = 5
}
#Test
fun test(){
var sample = Sample()
sample = mockk {
every { returnFive() } returns 10
}
assertEquals(5,sample.returnFive())
}
Your code can be rewritten as
class Sample {
fun returnFive() = 5
}
#Test
fun test() {
val sample: Sample = mockk()
every { sample.returnFive() } returns 10
assertEquals(10, sample.returnFive())
}
This allows us to see that sample becomes an instance of Sample, but Mockk is creating it, not you.
When you delegate this creation to Mockk, it does some magic to replace that instance with an instrumented one, which you can define extra behaviours. Mockk's author explained a little bit more about this in this blog post if you're interested.
Could it be related to Kotlin?
This isn't exactly Kotlin's behaviour.
You could do the same thing when using Java with Mockito, for example.

How to create a TestContainers base test class in Kotlin with JUnit 5

I am trying to use Neo4j TestContainers with Kotlin, Spring Data Neo4j, Spring Boot and JUnit 5. I have a lot of tests that require to use the test container. Ideally, I would like to avoid copying the container definition and configuration in each test class.
Currently I have something like:
#Testcontainers
#DataNeo4jTest
#Import(Neo4jConfiguration::class, Neo4jTestConfiguration::class)
class ContainerTest(#Autowired private val repository: XYZRepository) {
companion object {
const val IMAGE_NAME = "neo4j"
const val TAG_NAME = "3.5.5"
#Container
#JvmStatic
val databaseServer: KtNeo4jContainer = KtNeo4jContainer("$IMAGE_NAME:$TAG_NAME")
.withoutAuthentication()
}
#TestConfiguration
internal class Config {
#Bean
fun configuration(): Configuration = Configuration.Builder()
.uri(databaseServer.getBoltUrl())
.build()
}
#Test
#DisplayName("Create xyz")
fun testCreateXYZ() {
// ...
}
}
class KtNeo4jContainer(val imageName: String) : Neo4jContainer<KtNeo4jContainer>(imageName)
How can I extract the databaseServer definition and the #TestConfiguration? I tried different ways of creating a base class and having the ContainerTest extend it, but it is not working. From what I understand, static attriubutes are not inherited in Kotlin.
Below my solution for sharing same container between tests.
#Testcontainers
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
abstract class IntegrationTest {
companion object {
#JvmStatic
private val mongoDBContainer = MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))
.waitingFor(HostPortWaitStrategy())
#BeforeAll
#JvmStatic
fun beforeAll() {
mongoDBContainer.start()
}
#JvmStatic
#DynamicPropertySource
fun registerDynamicProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.data.mongodb.host", mongoDBContainer::getHost)
registry.add("spring.data.mongodb.port", mongoDBContainer::getFirstMappedPort)
}
}
}
The key here is to not use #Container annotation as it will close just created container after your first test subclass executes all tests.
Method start() in beforeAll() initialize container only once (upon first subclass test execution), then does nothing while container is running.
By theory we shouldn't have to do this hack, based on:
https://www.testcontainers.org/test_framework_integration/junit_5/
...container that is static should not be closed until all of tests of all subclasses are finished, but it's not working that way and I don't know why. Would be nice to have some answer on that :).
I've had the same issue (making Spring Boot + Kotlin + Testcontainers work together) and after searching the web for (quite) a while I found this nice solution: https://github.com/larmic/testcontainers-junit5. You'll just have to adopt it to your database.
I faced very similar issue in Kotlin and spring boot 2.4.0.
The way you can reuse one testcontainer configuration can be achieved through initializers, e.g.:
https://dev.to/silaev/the-testcontainers-mongodb-module-and-spring-data-mongodb-in-action-53ng or https://nirajsonawane.github.io/2019/12/25/Testcontainers-With-Spring-Boot-For-Integration-Testing/ (java versions)
I wanted to use also new approach of having dynamicProperties and it worked out of a boxed in java. In Kotlin I made sth like this (I wasn't able to make #Testcontainer annotations working for some reason). It's not very elegant but pretty simple solution that worked for me:
MongoContainerConfig class:
import org.testcontainers.containers.MongoDBContainer
class MongoContainerConfig {
companion object {
#JvmStatic
val mongoDBContainer = MongoDBContainer("mongo:4.4.2")
}
init {
mongoDBContainer.start()
}
}
Test class:
#SpringBootTest(
classes = [MongoContainerConfig::class]
)
internal class SomeTest {
companion object {
#JvmStatic
#DynamicPropertySource
fun setProperties(registry: DynamicPropertyRegistry) {
registry.add("mongodb.uri") {
MongoContainerConfig.mongoDBContainer.replicaSetUrl
}
}
}
Disadvantage is this block with properties in every test class what suggests that maybe approach with initializers is desired here.

How to create Mockito mock with constructor parameters in Kotlin?

I'd want to use doReturn(sth).when(underTest).someFunc() instead of when(underTest.someFunc()).thenReturn(sth).
(don't want to actually execute anything inside someFunc() - https://stackoverflow.com/a/29394497/541624)
In Java, I could do underTest = Mockito.spy(new SomeClass(someParam));
I'm getting:
Mockito cannot mock/spy because :
- final class
The reason you cannot mock/spy Kotlin classes is they are final (by default). So Mockito cannot mock such classes unless you put the keyword open.
The Mockito version 2 introduced a feature which allows you to mock/spy final classes.
How to do it?
Add mockito-inline dependency with other mockito v2 dependencies. For ex: testImplementation 'org.mockito:mockito-inline:2.8.9'
Then use mockito methods as normal.
Here's a dummy test which demonstrates how to mock a method and do nothing.
class Foo {
var xval = 0
fun foo(x: Int, y: Int): Int = x / y
fun bar(x: Int) {
xval = x
}
}
class FooTest {
#Test
fun fooTest() {
val foo = Mockito.mock(Foo::class.java)
Mockito.doAnswer(Answers.RETURNS_DEFAULTS).`when`(foo).foo(10, 2)
assertEquals(0, foo.foo(10, 2))
Mockito.doNothing().`when`(foo).bar(100)
assertEquals(0, foo.xval)
}
}
As you can see, you could return defaults for methods which return something or do nothing for void methods.
Otherwise, you could use mockk https://mockk.io/ library which doesn't have this issue.
Having said all the above, I suggest that think if you could use an interface/abstract class rather than a concrete class here. That’s the best way to abstract away your dependency using mocking.

unit testing extension function and mocking the other methods of the class

I am writing an extension function adding some retry capabilities to AmazonKinesis.putRecords. In my extension method i do some logic and some calls to the original putRecords method:
fun AmazonKinesis.putRecordsWithRetry(records: List<PutRecordsRequestEntry>, streamName: String) {
//...
val putRecordResult = this.putRecords(PutRecordsRequest().withStreamName(streamName).withRecords(records))
//...
}
From a unit test point of view I am finding it hard to see how I should mock the call to this.putRecords
I am using com.nhaarman.mockitokotlin2.*
val successfulRequest = PutRecordsResultEntry().withErrorCode(null);
class KinesisExtensionTest : StringSpec({
val testRecords = ArrayList<PutRecordsRequestEntry>()
testRecords.add(PutRecordsRequestEntry().withPartitionKey("iAmABunny").withData(ByteBuffer.wrap("aaa".toByteArray()))
)
val kinesis = mock<AmazonKinesis>{
on { putRecordsWithRetry(testRecords, "/dev/null") }.thenCallRealMethod()
on { putRecords(any()) }.thenReturn(PutRecordsResult().withRecords(listOf(successfulRequest, successfulRequest)))
}
"can write a record" {
kinesis.putRecordsWithRetry(testRecords, "/dev/null")
verify(kinesis).putRecord(any())
}
})
The putRecordResult is always null
The extension function AmazonKinesis.putRecordsWithRetry will be compiled to a static function under the hood, and Mockito doesn't support static method mocking yet.
Therefore Mockito may not know the stubbing information at the verification step and thus the default null value is produced.