I have two integration tests:
test1:
#Rollback(false)
#SpringBootTest(
classes = {Application.class, Config.class},
webEnvironment = WebEnvironment.RANDOM_PORT)
#ActiveProfiles( "pr1")
public class Test1 {
}
test2:
#Rollback(false)
#SpringBootTest(
classes = {Application.class, Config.class},
webEnvironment = WebEnvironment.RANDOM_PORT)
#ActiveProfiles( "pr2")
public class Test2 {
}
When I run all the tests together, the test 2 is using the context of test 1, which couse the test to fail.
From logs I can see that two application contexts are created for each profile.
If you want to fully separate the test contexts you must use #DirtiesContext
#DirtiesContext
#SpringBootTest
void Test {
...
}
Read more about that configuration: https://www.baeldung.com/spring-dirtiescontext
Related
I have a set of Junit test cases for a Spring Boot application which are annotated with #EnableCaching annotation. When these Junit tests are run individually it works fine. But when run together with the other Junit test classes , the #EnableCaching annotation seems to get ignored.
I'm using the #DirtiesContext annotation to clean the context after each test method. But this doesnt seem to be making any difference to the above mentioned issue.
Please let me know if #EnableCaching can be used in Junit Tests or not.
Please find below a sample code of the Junit Test class.
#EnableCaching
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#TestPropertySource(properties = { "a,b,c" })
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class SampleTest {
#BeforeEach
void setUpTest() {
//setup steps
}
#Test
void testCacheable(){
String result = controller.testCache();
}
}
#RestController
public class TestController {
#RequestMapping("/testCache")
#Cacheable(cacheNames="cache")
public String testCache() throws InterruptedException {
logger.info("Returning NOT from cache");
return "cache";
}
}
I have a SpringBoot Project and it has two classes annotated with #SpringBootApplication.
I have written a junit test like this
#RunWith(SpringRunner.class)
#WebMvcTest(value = TestController.class)
public class Test1 {
#Test
public void test1(){
}
}
When i run this test am getting exception
java.lang.IllegalStateException: Found multiple #SpringBootConfiguration annotated classes.
I want the test to load only the controller and not the complete context.
Any help on this?
Try to add #ContextConfiguration annotation to your test class.
#RunWith(SpringRunner.class)
#ContextConfiguration(classes=Application.class)
#WebMvcTest(value = TestController.class)
public class Test1 {
#Test
public void test1(){
}
}
When writing Spring tests using both #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) and #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT), I am seeing the tests reuse the same application context.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class DemoApplicationTestsDefinedPort {
#Test
void testDefinedPort() {}
}
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class DemoApplicationTestsMock {
#Test
void mockTest() {}
}
With logging.level.org.springframework.test.context.cache=DEBUG, the relevant log output:
...
Storing ApplicationContext [912966811] in cache under key [[WebMergedContextConfiguration#74287ea3 testClass = DemoApplicationTestsDefinedPort, ...]]
...
Retrieved ApplicationContext [912966811] from cache with key [[WebMergedContextConfiguration#4dad8ec0 testClass = DemoApplicationTestsMock, ...]]
...
testDefinedPort expects a real server to be started on the port specified by server.port. However, depending on the order of execution testDefinedPort may instead reuse the application context created by mockTest. Is this behaviour expected?
Update: Raised and identified as a bug - https://github.com/spring-projects/spring-boot/issues/23085
I am using #SpringBatchTest to run e2e tests on my Spring Batch application.
Everything works well except when I run both of my test classes (divided my tests into positive/negative test classes) together. The first one runs and tests pass, but the second fails trying to launch the context again. Since it is already launched, the tests fail on InstanceAlreadyExistsException.
Both my test classes are defined with the following annotations:
#RunWith(SpringRunner.class)
#SpringBatchTest
#EnableAutoConfiguration
#ContextConfiguration(classes = {MyTestConfiguration.class})
#TestExecutionListeners({MockitoTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
EDIT:
In general, what my test does is:
#RunWith(SpringRunner.class)
#SpringBatchTest
#EnableAutoConfiguration
#ContextConfiguration(classes = {HardDeleteTestConfiguration.class})
#TestExecutionListeners({MockitoTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class TestClass1 {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils;
#Before
public void setUp() {
jobRepositoryTestUtils.removeJobExecutions();
}
#Test
public void SpringBatchTest() {
// preparing data for test
// ...
JobExecution jobExecution =
jobLauncherTestUtils.launchJob(createJobParams("myKey","myValue"));
// Perform assertions
// ...
}
}
private void createJobParams(String key, value) {
JobParameters uniqueJobParameters = jobLauncherTestUtils.getUniqueJobParameters();
JobParametersBuilder paramsBuilder = new JobParametersBuilder(uniqueJobParameters);
paramsBuilder.addString(key, value);
return paramsBuilder.toJobParameters();
}
}
TestClass2 is the same as TestClass1 with only different data preparation and assertions.
Also my test properties are as follows:
# Spring Boot configuration
spring.main.allow-bean-definition-overriding=true
spring.batch.job.enabled=false
# Spring Batch configuration
spring.batch.job.names=myBatchJob
I have tried all combinations of true and false for the previous flags but it does not make any difference.
Since it is already launched, the tests fail on InstanceAlreadyExistsException.
This means the datasource is reused between tests, and when the second test runs, it will try to launch the same job instance.
In your createJobParameters() method, you can use JobLauncherTestUtils#getUniqueJobParameters to create unique job parameters and run a different job instance for each test.
Eventually we realized it was an in-house framework wrapping Spring that caused the problem (stupid static instantiations on context loading and such).
To solve we used #MockBean on one problematic class, and #EnableAutoConfiguration( exclude = ProblematicConfiguration.class) in the annotation located above the test class.
I am able to run each #DataJpaTest separately from eclipse.
My #DataJpaTest is something like below:
#RunWith(SpringRunner.class)
#DataJpaTest
#Import(UserDataOnDemand.class)
#AutoConfigureTestDatabase(replace = Replace.NONE)
public class UserIntegrationTest {
......
}
Is there any way to run all #DataJpaTest classes at once ?
You have two options really.
Include all the tests in the same package and run all the tests in that package.
Include all your #DataJpaTest annotated classes in a test suite class and run this:
#RunWith(Suite.class)
#SuiteClasses({ DataJpaTest1.class, DataJpaTest2.class })
public class MyTestSuite {
}