Does Juint reset global variables for each test? - spring

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.

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).

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

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.

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.

groovy spock mocking spring autowired beans

I have bean:
#Service
public class EQueueBookingService {
#Autowired
public EQueueBookingClient eQueueBookingClient;
And I try to write some test for this bean EQueueBookingService using Spock.
https://code.google.com/p/spock/wiki/SpockBasics
My mock is
class EQueueBookingServiceTest extends Specification {
#Autowired
EQueueBookingService testedService;
EQueueBookingClient eQueueBookingClient = Mock(EQueueBookingClient);
def setup() {
testedService.eQueueBookingClient = eQueueBookingClient;
}
and test method:
...
setup:
CancelBookingResponse response = new CancelBookingResponse();
...
eQueueBookingClient.cancelBooking(_, _) >> response;
when:
def result = testedService.cancelBooking(request);
then:
result != null && result.bookId == bookId
Why eQueueBookingClient doesn't mock?
When I debug it: in test - I see Mock instance, when I go to method - I see real bean instance.
Thanks a lot!
I've found solution!
need implement setter for this client and use it in setup like:
private EQueueBookingClient eQueueBookingClient = Mock(EQueueBookingClient);
def setup() {
testedService.setBookingClient(eQueueBookingClient);
}
If define client in service as public and use = it doesn't work;
For example:
testedService.eQueueBookingClient = eQueueBookingClient;//mocked instance doesn't work

Resources