Mockk "verify" takes up to 6 seconds when verifying method with 3 or more parameters - spring

I use mockk (versions 1.12.0 and 1.12.3) in #SpringBootTest in order to create a spy of some service and verify later that the service's method was (or was not) called. This looks like this:
#SpringBootTest
class MyTests {
#Autowired
private lateinit var someBean: SomeBean
#TestConfiguration
class Config {
#Bean
#Primary
fun someBeanSpy(someBean: SomeBean) = spyk(someBean)
}
#BeforeEach
internal fun setUp() {
clearAllMocks()
}
#ParameterizedTest
#MethodSource("data")
fun `some test`(s: String) {
// prepare data and call controller
verify(exactly = 0) { someBean.foo(any(), any(), any()) } // <- execution of this verify lasts about 6 seconds
// other verify statements last about 200ms
}
companion object {
#JvmStatic
fun data(): Stream<Arguments> = Stream.of(Arguments.of("abc"), Arguments.of("cde"))
}
}
However, the execution of verify method on spy's methods with 3 or more parameters take too long time. Why may I have such behavior?
The same works fine with Mockito, but I don't want to use it with Kotlin because than I can't use just regular Mockito#any with non-nullable types.
Also, when I reduced the SomeBean#foo method's number of parameters from 3 to 2, verify executed just as normal, about 200ms.

Related

changing configuration value in spring-boot app with values of parameterized test

I use this in my MyService.kt.
The useXml is read via application.yml and application-test.yml
#Service
class MyService (
#Value("\${something.use-xml}")
var useXml: Boolean = false
) {
if(useXml) {
// do this
} else {
// do that
}
....
}
this works as expected.
but for the testing I want to use both variation:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyFunctionalTest {
#Value("\${something.use-xml}")
var useXml: Boolean = false
//....
#ParameterizedTest
#ValueSource(booleans = [true,false])
fun `do a parameterized test`(useXML : Boolean) {
useXml = useXML // this is (of course) not setting the variations for `MyService.kt`
if (useXML) {
// test this
} else {
// test that
}
}
I want a possibility where I can set the variable for the application.yml file, so both variations are tested.
Is there any way of doing it?
Of course, it is possible. You need to inject the service that you are testing and set its useXml value. In your case, it'll look like this:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class MyServiceTest {
#Autowired
private lateinit var myService: MyService
#ParameterizedTest
#ValueSource(booleans = [true,false])
fun `do a parameterized test`(useXML : Boolean) {
myService.useXml = useXML // you have to set the value for the test case
Assertions.assertEquals(useXML, myService.useXml)
}
}
However, if I were you and have such a case, I'd go with two totally separate implementations of the same interface, if xml and the other format have something in common. In the end, you will have two classes (you need better naming for that):
MyServiceXml
MyServiceJson
Both this classes will be annotated will #ConditionalOnProperty("\${something.use-xml}") and they will be implementing the same interface.
That will be very easy to test, two different implementations, so two different test classes.

spring junit test data preparrer class access repositories trough field

I have simple class annotated with #Component and injected repositories like
#Component
class TestsDataPreparer(
private val carRepository: CarRepository
) {
fun withCar(builder: Car.() -> Unit = {}): Car {
return carRepository.save(
Car(
name = builder.name!!
)
)
}
}
which is clear..
But i wonder if it would be ok to do something like this, or if it is considered as anti-pattern.
#Component
class TestsDataPreparer(
val carRepository: CarRepository
) {
fun withCar(builder: Car.() -> Unit = {}): Car {
return carRepository.save(
Car(
name = builder.name!!
)
)
}
}
#Test
fun testCar() {
testsDataPreparer.withCar{this.name="Super-cool-car!"}
assertThat(testsDataPreparer.carRepository.findAll()).hasSize(1)
}
So the question is if it is okay to not inject repository in test class itself, but reuse it from TestsDataPreparer class
Yes, making an originally private field public just for testing can be considered an antipattern. Instead, you can create a CarRepository instance and then pass it to TestsDataPreparer when you create it. But for unit testing, you don't actually need that, you can use a mock and verify that the correct method was called (CarRepository.save).

Does Juint reset global variables for each test?

I have an integration test class like this (but more complex)
#ExtendWith(SpringExtension::class)
#WebMvcTest(Controller::class)
class ScheduleControllerTest(#Autowired val mockMvc: MockMvc) {
val obj = object {
var b = 2
}
#Test
fun a(){
obj.b = 1
assertEquals(obj.b, 1)
}
#Test
fun b(){
assertEquals(obj.b, 2)
}
}
and all tests in this class pass as if after each test obj is reset to its initial value. No #Before functions are used here, so what is happening?
By default JUnit creates a new test class instance for each test run (fields are initialized anew each time). You can modify this behavior by using the #TestInstance annotation.

JUnit #BeforeClass non-static work around for Spring Boot application

JUnit's #BeforeClass annotation must be declared static if you want it to run once before all the #Test methods. However, this cannot be used with dependency injection.
I want to clean up a database that I #Autowire with Spring Boot, once before I run my JUnit tests. I cannot #Autowire static fields so I need to think of a work around. Any ideas?
Just use #Before (instead of #BeforeClass) (or Spring's #BeforeTransaction (depending on how you initialize the database)). This annotation must been attached to an nonstatic public method.
Of course: #Before run before EACH test case method (not like #BeforeClass that runs only once.) But if you want to run it exactly once, then use an static marker field.
private static boolean initialized = false;
...
#Before
public void initializeDB() {
if (!initialized) {
... //your db initialization
initialized = true;
}
}
---
For JUnit5: Test Execution Order and #TestInstance(Lifecycle.PER_CLASS)
Kotlin example:
#ExtendWith(SpringExtension::class)
#TestInstance(PER_CLASS)
class BeforeInstanceTests {
private var initialized: String = ""
private val callList: MutableList<String> = ArrayList()
#BeforeAll
fun beforeAllNonStatic() {
initialized = "initialized"
assertEquals(0, callList.size)
}
#Test
fun test1() {
assertEquals("initialized", initialized)
callList.add("test1")
}
#Test
fun test2() {
assertEquals("initialized", initialized)
callList.add("test2")
}
#Test
fun test3() {
assertEquals("initialized", initialized)
callList.add("test3")
}
#AfterAll
fun afterAllNonStatic() {
assertEquals("initialized", initialized)
assertEquals(3, callList.size)
assertTrue(callList.contains("test1"))
assertTrue(callList.contains("test2"))
assertTrue(callList.contains("test3"))
callList.clear()
initialized = ""
}
}
Have a look at the DBUnit library - it's designed to perform the actions you're describing. It can create & tear down database instances and provides you with simple ways to do this.
Though accepted answer is clever, seems hacky. Have you tried using a normal Constructor?
public class MyJUnitTest {
public MyJUnitTest() {
// code for initializeDB
}
// Tests
}
Try this solution:
https://stackoverflow.com/a/46274919/907576 :
with #BeforeAllMethods/#AfterAllMethods annotations you could execute any method in Test class in an instance context, where all injected values are available.

How to wait for transactions to commit using Propagation REQUIRES_NEW

I want to integration test a service method that calls a method that uses #Transactional(propagation = Propagation.REQUIRES_NEW). However, assertions based on the inner (new) transaction fail.
class MyService {
#Transactional(propagation = Propagation.NESTED)
def method1() {
method2()
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
def method2() {
// some code that will modify the DB
}
}
class MyServiceNonTransactionalIntegrationSpec extends IntegrationSpec {
static transactional = false
def myService = new MyService()
setup() {
// populate database here
}
cleanup() {
// teardown database here after tests complete
}
def method1() {
when: "we test the main method"
myService.method1()
then: "we should be able to see the result of method 1 and method 2"
// BUT: (!!!)
// assertions based on state of database fail, perhaps because new transaction
// wrapped around method 2 has not yet committed
}
}
How do I integration test method1()?
EDIT:
In an attempt to work around the proxy issue, I've tried the following, but still can't get it to work:
class MyService {
def myService2
#Transactional(propagation = Propagation.NESTED)
def method1() {
myService2.method2()
}
}
class MyService2 {
#Transactional(propagation = Propagation.REQUIRES_NEW)
def method2() {
// some code that will modify the DB
}
}
class MyServiceNonTransactionalIntegrationSpec extends IntegrationSpec {
static transactional = false
def myService = new MyService()
def myService2 = new MyService2()
setup() {
myService.myService2 = myService2
// populate database here
}
// rest as before
}
It's only a self-invoking problem if you're using org.springframework.transaction.annotation.Transactional - you should be using #grails.transaction.Transactional instead which has the same configuration options but uses AST transforms instead of runtime proxies to avoid the issue of not calling the proxied method. When using the Grails annotation each method is rewritten to simulate creating a proxy for each one, wrapping the code in a transaction template that's configured based on the annotation settings for that method (either explicit on the method, or inferred from a class-scope annotation).
But your tests are broken because you're using new to create the services. Always use dependency injection in integration tests so you get the configured Spring bean, not just a new uninitialized POGO. To do this, add the same property syntax you would outside of your tests:
def myService
def myService2
and remove unnecessary wiring code (e.g. myService.myService2 = myService2) that Spring does for you.
You've faced self-invoking. Look here: Spring - #Transactional - What happens in background? or Spring #Transactional Annotation : Self Invocation
Here is excerption from one of my classes:
#Service("authzService")
public class AuthorizationService implements IAuthorizationService {
#Resource(name="authzService")
private IAuthorizationService self;
I use this private member for self invoke methods with #Cached annotation.

Resources