I'm using Junit5 and Spring for test.
I want to initalize spring bean for each test because I don't want different tests to change the other results of tests.
I'm knowing that a new instance of the test class is created before running each test method by default. under result of test codes is true,because the instance variable number is initalized for each test by junit5.
public class TestInstanceVaribale{
int number = 0;
#Test
public void test1() {
number += 3;
Assertions.assertEquals(3, number);
}
#Test
public void test2() {
number += 5;
Assertions.assertEquals(5, number);
}
}
but, this code is failed because spring bean is not initalized.
#Component
public class Car {
public String name = "myCar";
}
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
#SpringBootTest
#TestMethodOrder(OrderAnnotation.class)
public class TestSpringVariable {
#Autowired
Car car;
#Test
#Order(1)
public void test1() {
car.name = "testCar";
Assertions.assertEquals("testCar", car.name);
}
#Test
#Order(2)
public void test2() {
// this is fail. expected: <myCar> but was: <testCar>
// but I want expected: <myCar> but was: <myCar>
Assertions.assertEquals("myCar", car.name);
}
}
How to initalize spring bean for separation between tests in junit?
#SpringBootTest
#initalizeSpringBeanPerMethod <-- I want like this
public class TestSpringVariable2 {
#Autowired
Car car;
#BeforeEach
public void initalize() { <-- I want like this
SpirngBean.initalize()
}
}
Take a look at DirtiesContext
Probably adding this to your class should work. It's telling Spring to reset it's state after/before (depending on how you set it) each test
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
Related
My Spring Boot app has some test that are reading their properties from the application.yml that is in the test folder.
cat:
maxAge:30
maxNameSize:10
all is working fine, but I like that in certain tests, other values will be injected:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
Cat.class
})
#SpringBootTest
public class CatTest {
#Test
public void testX(){
//inject maxAge=90
// use maxNameSize from the application.yml
....
#Test
public void testZ(){
//inject maxNameSize=5
// use maxAge from the application.yml
....
}
Changing properties on method level is not supported by Spring at this moment.
You can use nested classes to accomplish this.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
Cat.class
})
#SpringBootTest
public class CatTest {
#Nested
#SpringBootTest(properties = "cat.maxAge=90")
public class NestedTestX {
#Test
void testX() {
//noop
}
}
#Nested
#SpringBootTest(properties = "cat.maxNameSize=5")
public class NestedTestZ {
#Test
void testZ() {
//noop
}
}
}
I have the following Spring Service class that I'm trying to test with Mockito:
#Service
public class ObjectExportService {
#Autowired
protected List<SecuredService<? extends SecuredObject>> securedServices;
public void doStuff() {
for(int i = 0; i < this.securedServices.size(); i++){
SecuredService<? extends SecuredObject> securedSrv = this.securedServices.get(i);
//this access works
}
for (SecuredService<? extends SecuredObject> securedSrv : this.securedServices) { //this access does not work
}
}
}
This is my Test class for that service:
#RunWith(MockitoJUnitRunner.class)
public class ObjectExportServiceTest {
#InjectMocks
private ObjectExportService objectExportService;
#Mock
protected List<SecuredService<? extends SecuredObject>> securedServices;
#Test
public void testDoStuff(){
objectExportService.doStuff();
Assert.assertTrue(true);
}
}
When I run the test, I get a NullpointerException, but only in the for-each loop.
First I assumed is a similar problem as described in this thread:
I have Mocked the List and would therefore need to mock the iterator() call.
The solutions provided in that thread didn't work for me, because I am actually autowiring a List.
So I stumbled across this solution in another thread. Simply changing the #Mock to #Spy resolved the issue for me:
#RunWith(MockitoJUnitRunner.class)
public class ObjectExportServiceTest {
#InjectMocks
private ObjectExportService objectExportService;
#Spy // <-- change here
protected List<SecuredService<? extends SecuredObject>> securedServices;
#Test
public void testDoStuff(){
objectExportService.doStuff();
Assert.assertTrue(true);
}
}
My Service class uses a property set it application.properties
#Service
public class Service {
#Value("${my.prop}")
private String prop;
public Response doWork(String param1,String param2){
System.out.println(prop); //NULL!!!
}
}
I want to test it and set my own value:
Test Class:
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource(locations = "application.properties",properties = { "my.prop=boo" })
public class ServiceUnitTest {
#InjectMocks
private Service service;
#Test
public void fooTest(){
Response re = service.doWork("boo", "foo");
}
}
But when I run the test, the value is null (not even the value that exists in application.properties).
I don't have experience with MockitoJUnitRunner, but I am able to achieve this using PowerMockRunner.
Set up the application context with a test configuration, and autowire the bean from you application context into your test class. You also shouldn't need the "locations = " bit in the #TestPropertySource annotation.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
#TestPropertySource(properties = { "my.prop=boo" })
public class ServiceUnitTest {
#TestConfiguration
static class ServiceUnitTestConfig {
#Bean
public Service service() {
return new Service();
}
}
#Autowired
Service service;
#Test
public void fooTest(){
Response re = service.doWork("boo", "foo");
}
}
I have a class:
#Component
public class B {
#Autowired
private A a;
}
and A is a component:
#Component
public class A{}
In unit test class BTest:
public class BTest {
#Test
public void testBMethod() {
}
}
I am not using an xml to define context or for beans to be picked from.
What is the cleanest way I can get the test to run?
You don't have to use Spring for the unit tests. Mockito may be used for this.
public class BTest {
#Mock
private A a;
#Mock
private B b;
#Test
public void testBMethod() {
}
}
For more details, you may check https://springframework.guru/mocking-unit-tests-mockito/
and https://dzone.com/articles/use-mockito-mock-autowired
I am writing a functional test using cucumber for my Spring boot application. The logic which I want to test uses current time, based on that the result vary. Is there a way to mock the current time in functional tests
That's possible using PowerMock http://powermock.github.io/
#RunWith(PowerMockRunner.class)
// ... other annotations
public class SomeTest {
private final Date fixedDate = new Date(10000);
#Before
public void setUp() throws Exception {
PowerMockito.whenNew(Date.class).withNoArguments().thenReturn(fixedDate);
}
...
}
Another approach is to use some service that provides current time and mock this service in the test. Rough example
#Service
public class DateProvider {
public Date current() { return new Date(); }
}
#Service
public class CurrentDateConsumer {
#Autowired DateProvider dateProvider;
public void doSomeBusiness() {
Date current = dateProvider.current();
// ... use current date
}
}
#RunWith(Cucumber.class)
public class CurrentDateConsumerTest {
private final Date fixedDate = new Date(10000);
#Mock DateProvider dateProvider;
#Before
public void setUp() throws Exception {
when(dateProvider.current()).thenReturn(fixedDate);
}
}