I am using junit 4.11 and spring-test-4.1.5 for writing integration test cases. I am using #ContextConfiguration annotation to load the configurations.like,
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes ={ApplicationConfig.class,SpringConfiguration.class }, initializers = {CustomProfileResolver.class, AppInitializer.class}, loader = SpringApplicationContextLoader.class)
As you can see i am using two configuration classes.
The problem i am facing is i want to load the SpringConfiguration.class before ApplicationConfig.class. I tried with reversing the order but it didn't worked. Neither #order can be specified here.
So how to order the loading of these configuration classes, is it possible ?
#ContextConfiguration and its supporting classes (e.g., MergedContextConfiguration, AnnotationConfigContextLoader, AbstractTestContextBootstrapper, etc.) are intended to retain the original ordering of #Configuration classes declared via the classes attribute of #ContextConfiguration.
Thus, if you can verifiably prove that reversing the order of your SpringConfiguration and ApplicationConfig classes does not result in SpringConfiguration being processed first, then you have found a bug in Spring.
If you have found a bug, please report it in JIRA.
Thanks,
Sam
Use #ContextHierarchy
#ContextHierarchy({
#ContextConfiguration(classes = {SpringConfiguration.class}),
#ContextConfiguration(classes = {ApplicationConfig.class})
}
Related
I am trying to test a JAX-RS application but I'd rather not mock the data especially since there's a buildData method for an existing #DataJpaTest
Here's what I am trying so far:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = MyApp.class
)
#DirtiesContext
#DataJpaTest
public class MyResourceTest {
I get the following error
java.lang.IllegalStateException: Configuration error: found multiple declarations of #BootstrapWith for test class [app.MyResourceTest]: [#org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.context.SpringBootTestContextBootstrapper), #org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper)]
The other ones I saw that are similar do not talk about the webEnvironment setting:
How do I import configuration classes in a #DataJpaTest in a SpringBootTest?
Recommended way to remove #DataJpaTest when used along with #SpringBootTest
There is somewhat of a solution using #AutoConfigureTestDatabase but when I did that only the first one works because buildData is annotated with #Before (same as in #DataJpaTest) as I want the data to be pristine before each test so I can do failure scenarios.
Switching to #BeforeClass also won't work because I won't be able to use the #Autowire Repository objects.
The #DataJpaTest documentation states the following:
If you are looking to load your full application configuration, but use an embedded database, you should consider #SpringBootTest combined with #AutoConfigureTestDatabase rather than this annotation.
Keep in mind that #DataJpaTest is annotated with #Transactional and #DirtiesContext. So you may need those annotations along with #AutoConfigureTestDatabase.
Actually when doing the answer in https://stackoverflow.com/a/57609911/242042, it solves the immediate problem, but you won't be able to do any tests that involve the database using a REST client as #Transactional will prevent the data from being saved for the client to get.
To get this to work, #Transactional should not be used. Instead DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD should be used instead. This dramatically slows down each test (as in 1 second to 10 seconds per test) but at least it works.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = MyApp.class
)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#AutoConfigureTestDatabase
#AutoConfigureWebTestClient
public class MyResourceTest {
#Autowired
private TestRestTemplate restTemplate;
...
}
We have an application that relies on Spring Boot 2.0. We are in the process of migrating it to JDK11 from JDK8. This also enabled us to update Spring Boot from 2.0 to 2.1. After reading through the changelog, it appeared there was any major change that needed for us.
Now the problem lies in where some test classes are annotated with both #SpringBootTest and #DataJpaTest. As per this and as well as the documentation, we are not supposed to use both together and instead we changed #DataJpaTest to #AutoConfigureTestDatabase. Here is how the code is:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {A.class, B.class}, properties = {
"x=xxx",
"y=yyy"
})
#AutoConfigureTestDatabase // Used to be #DataJpaTest
#EnableJpaRepositories("com.test")
#EntityScan("com.test")
public class Test {
#TestConfiguration
public static class TestConfig {
// Some beans returning
}
// Tests
}
Now, we end up with the following error:
NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
So as per this answer, we did something like this:
#EnableJpaRepositories(basePackages="com.test", entityManagerFactoryRef="entityManagerFactory")
Even after this we still end up with the same error. Is this the right way to remove #DataJpaTest? Or do we need to remove #SpringBootTest and do something else? Any sort of guidance is much appreciated.
The testclass is annotated with #DataJpaTest and #ContextConfiguration
#RunWith(SpringRunner.class)
#DataJpaTest
#ContextConfiguration(locations = { "classpath:test-context.xml" })
public abstract class AbstractTestCase {
protected static final Logger LOG = LoggerFactory.getLogger(AbstractTestCase.class);
}
We defined a test-context.xml. This is because the testmodule is isolated from all other modules (multi maven module project). In the test-context.xml we defined the component-scan for the base-package.
<context:component-scan base-package="de.example.base.package" />
I have src/main/test/resources/application-test.yml, as per SpringBootTest it will load application.yml and then loads application-test.yml. But I face a scenario where I want to override certain properties in application-test.yml only for one test but other test needs to use properties from application-test.yml. How would I do this ?
I tried to use the #TestPropertySource annotation to override but it is not working.
#Slf4j
#RunWith(SpringRunner.class)
#SpringBootTest(classes= MyApplicationTestApplication.class)
#ActiveProfiles("test")
#DirtiesContext
#TestPropertySource(locations = {"classpath:application-test.yml",
"classpath:file-test.properties"})
Thanks for comments and answer , just wanted to add which worked for me
#SpringBootTest(properties = "some.property=localhost:9094")
Link to doc
What about creating one more profile and activate both of them (order matters) #ActiveProfiles({"test", "test-override"})
Or you can just override using System.properties, for example in static block, before spring context starts loading itself.
I've been running into #ComponentScan issues with #Configuration classes for tests -- namely, the #ComponentScan is pulling in unintended #Configuration during integration tests.
For example, say you've got some global config in src/main/java which pulls in components within com.example.service, com.example.config.GlobalConfiguration:
package com.example.config;
...
#Configuration
#ComponentScan(basePackageClasses = ServiceA.class)
public class GlobalConfiguration {
...
}
It's intended to pull in two services, com.example.services.ServiceA and com.example.services.ServiceB, annotated with #Component and #Profile("!test") (omitted for brevity).
Then in src/test/java, com.example.services.ServiceATest:
package com.example.services;
...
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ServiceATest.ServiceATestConfiguration.class)
public class ServiceATest {
...
#Configuration
public static class ServiceATestConfiguration {
#Bean
public ServiceA serviceA() {
return ServiceA(somemocking...);
}
}
}
And also com.example.ServiceBIntegrationTest, which needs to pull in GlobalConfiguration.class in order to be an integration test, but still avoids pulling in dangerous implementations with #ActiveProfiles("test"):
package com.example.services;
...
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
#ContextConfiguration(classes = {GlobalConfiguration.class, ServiceBIntegrationTest.ServiceBIntegrationTestConfiguration.class})
public class ServiceBIntegrationTest {
...
#Configuration
public static class ServiceBIntegrationTestConfiguration {
#Bean
public ServiceB serviceB() {
return ServiceB(somemocking...);
}
}
}
The obvious intention of the ServiceBIntegrationTest is to pull in the complete src/main/java application configuration via GlobalConfiguration, exclude dangerous components via #ActiveProfiles("test") and replace those excluded components with its own implementations. However, during tests the namespace of src/main/java and src/test/java are combined, so GlobalConfiguration's #ComponentScan finds more in the classpath than it normally would -- namely, the ServiceA bean defined in ServiceA.ServiceATestConfiguration. That could easily lead to conflicts and unintended results.
Now, you could do something on GlobalConfiguration like #ComponentScan(..., excludeFilters= #ComponentScan.Filter(type = FilterType.REGEX, pattern = "\\.*(T|t)est\\.*")), but that has issues of its own. Relying on naming conventions is pretty brittle; still, even if you backed out a #TestConfiguration annotation and used FilterType.ANNOTATION, you'd effectively be making your src/main/java aware of your src/test/java, which it shouldn't be, IMO (see note below).
As it stands, I've solved my problem by using an additional profile. On ServiceA, I add a unique profile name -- so that its profile annotation becomes something like #ActiveProfiles("test,serviceatest"). Then, on ServiceATest.ServiceATestConfiguration I add the annotation #Profile("serviceatest"). This effectively limits the scope of ServiceATestConfiguration with relatively little overhead, but it seems like either:
a) I am using #ComponentScan incorrectly, or
b) There should be a much cleaner pattern for handling this problem
Which is it?
note: yes, the app is test-aware because it's using #Profile("!test"), but I'd argue making the application slightly test-aware to defend against improper resource usage and making it test-aware to ensure correctness of tests are very different things.
I see you are trying to fake Spring beans during integration test. If you combine #Profile and #ActiveProfiles annotation with #Primary annotation, most of your headaches should go away and you shouldn't need to mark production beans with #Profile("!test").
I wrote a blog post on the topic with Github examples.
Reaction on comment:
By package structure. Component scan scans all packages within current package and sub-packages. IF you don't want to scan beans, just amend your package structure the way that bean wouldn't be under your component scan umbrella.
Spring doesn't differentiate packages from src/test/java or src/main/java. Trying to exclude production beans with #Profile("!test") is design smell. You should avoid it. I would suggest to give a chance to approach from mentioned blog.
Notice that when you override the bean with #Primary annotation, you may need to use #DirtiesContext annotation to have clean sheet for other tests.
I have large number of test cases which runs with Spring Junit Support with following annotations on each Test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="classpath:spring/applicationContext.xml")
#TransactionConfiguration(transactionManager="transactionManager")
#Transactional
#ActiveProfiles("test")
Instead of putting all these annotations on each Test class I want to Create a Custom Annotation and use it.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="classpath:spring/applicationContext.xml")
#TransactionConfiguration(transactionManager="transactionManager")
#Transactional
#ActiveProfiles("test")
#Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface SpringJUnit4TestConfig {
}
But when I use this Custom Annotation Spring Injection is not happening at all.
#SpringJUnit4TestConfig
public class UserServiceTest
{
}
What I am missing here?
PS:
But JUnit's #RunWith and Spring's #Transactional, #ContextConfiguration all have #Inherited..So I thought it should work. But for now I get through it through a work around. Created a Based Abstract class and put all those Annotations on it and the test cases extending that Base class.
I don't think that this approach will work, as #RunWith is JUnit annotation, so for this to work JUnit annotations must be transitive.
When a class is annotated with #RunWith or extends a class annotated with #RunWith, JUnit will invoke the class it references to run the tests in that class instead of the runner built into JUnit. We added this feature late in development. While it seems powerful we expect the runner API to change as we learn how people really use it. Some of the classes that are currently internal will likely be refined and become public.
So test JUnit test invoking seem to work only for the inherited classes.
As for Spring, it supports a thing called context configuration inheritance for configuration locations, I'm quite not sure that this should work for other annotations types (please point me to the documentation, if you think otherwise) Actually, this will likely work for other annotations in case of test configuration class inheritance because #Transactional annotation itself is declared with #Inherited for this case.
So in this case, it does not run because of JUnit annotation's missing.