Spring configuration in test overriden by regular configuration - spring

I am having an issue where I've created a Configuration class for my source code, and a separate configuration class for my test package. I'd like some beans created differently in test than in other environments. However, when I run a build here's what's happening: (I have a bean called filesystem that gives me a virtual filesystem in test)
Overriding bean definition for bean 'fileSystem' with a different definition: replacing <testVersion from MockAppInjector> with <realVersionFromAppInjector>
I my test package I have
#Configuration
#ImportResource("classpath:/META-INF/fig-batch/spring-bootstrap.xml")
#ComponentScan(basePackages = "com.company")
class MockAppInjector {...}
and in my regular source package I have
#Configuration
#ImportResource("classpath:/META-INF/fig-batch/spring-bootstrap.xml")
#ComponentScan(basePackages = "com.company")
public class AppInjector {...}
And in my test I have #ContextConfiguration(classes = MockAppInjector.class)
Finally, all my xml has in it is <context:component-scan base-package="com.company" /> and a call to another xml that configures some data sources.

The problem is any beans defined in XML have more priority than beans defined in Java configuration for some reason. So if you test beans are defined in Java configuration it's expected behavior.
To solve it you have to either put your test beans into XML file and put it in #ImportResource after your prod XML file or mark your beans in Java configuration with #Primary annotation.

The problem was that my Test configuration class was finding my real one. So I added a filter
#ComponentScan(basePackages = "com.vanguard", excludeFilters = #ComponentScan.Filter(value=Configuration.class, type = FilterType.ANNOTATION))
And removed the component scan from the xml, since it was superfluous. Now everything gets loaded one time.

Related

Mock Bean for all JUnit Tests in Spring Boot

In Spring Boot, is there a way to mock a single bean for all existing JUnit tests, without changing the existing test classes (e.g., by adding an annotation or adding inheritance)? Like injecting a bean globally via configuration.
Assuming you are using #SpringBootApplication in your main sources to define the Spring Boot application, you'll already have component scanning enabled for everything in that package (including nested packages).
When running tests, the classes (typically) in src/test/java are also added to the classpath, and are therefore available to be scanned as well.
For example, if you defined your #SpringBootApplication at com.example.boot.MySpringBootApplication, then com.example.boot.MyTestConfiguration would be eligible for component scanning, even though the former is in src/main and the latter in src/test. Putting it in the src/test/java directory would ensure that it only has an effect while running tests.
You can then define any "global" beans you would like in that configuration.
Using the package/class names I provided:
// File: src/test/java/com/example/boot/MyTestConfiguration.java
#Configuration // this will get component-scanned
public class MyTestConfiguration {
#MockBean
MyBean myGlobalMockBean;
}
Then, so long as you don't omit that Configuration from the Context Configuration, the MockBean should always be present under test.

Configuration of SpringJUnit4ClassRunner Test clashes with SpringBootTest

I have a bunch of tests in my project that are all annotated with #SpringBootTest and therefore load up a SpringBoot context.
Now recently I refactored a Test in which I wanted a smaller scope (it´s about process coverage with camunda) to #RunWith(SpringJUnit4ClassRunner.class).
Since this means that no context is loaded automatically I create some beans "manually" with a static inner class configuration. The entire test looks something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
ExternalConfiguration.class, MyTest.InternalConfiguration.class
})
public class MyTest{
#Autowired
private SomeBean someInternalBean;
#Configuration
public static class InternalConfiguration{
#Bean
SomeBean someInternalBean() {
return mock(SomeBean .class);
}
}
//Tests
Now, this test runs fine when I run it. BUT when I run any other test ( those still annotated with #SpringBootTest), I get issues with when the ApplicationContext is loaded:
The bean 'someInternalBean', defined in class path resource [.../MyTest$InternalConfiguration.class], could not be registered. A bean with that name has already been defined in file [.../SomeBean.class] and overriding is disabled.
Apparently a bean is created when loading the ApplicationContext because the class is annotated with #Component AND the context loader tries to create another bean from my internal configuration.
I cant allow bean-overriding because my mock beans might overwrite the automatically created beans (which they do, I tried).
How do I circumvent this? I want my SpringJUnit4ClassRunner-tests with their internal configurations to not affect my other #SpringBootTest-tests. I already tried making the configuration beans conditional with #ConditionalOnMissingBean but that did not work.
Turns out those inner configuration classes should not be annotated with #Configuration. Removing the annotation makes it so that the manual bean generation still works and the configuration is no longer picked up by the componentScan.

Spring not recognising some #Configuration and #Component classes

I have - or rather had - a working Spring application, running within IntelliJ. It contains several classes annotated with #Configuration, and several #Component beans. At some point, the following happened:
Intelli started showing errors in the code editor stating "Could not autowire. No bean of 'xxx' type found". But there are such beans which are annotated with #Component.
Breakpoints in the constructor of specific #Component beans are not reached. But that is not true for all #Component beans.
When running in debug mode, breakpoints in certain #Configuration files are not reached, even though the debugger was stopping there before. The application will fail if it is autowired with one of these #Component beans.
The application starts without errors, but obviously without several beans configured in #Configuration classes being called.
The class which contains the main method which runs the Spring Boot application is annotated with #SpringBootApplication. #Component classes which live in the same package as this class are recognised and can be autowired, even into classes in other packages.
I am not aware of anything in the code or project which would have changed.
Under File -> Project Settings -> Modules, under Spring Application Context have now selected all #Configuration files. However this makes no difference.
Have also tried Build -> Rebuild Project.
The packages in which the classes reside have not changed. Has anyone seen anything like this before?
Thanks
If few classes are not getting recognised #Component. Then it could be the case that those classes don't come under the same package. You must have observed that the classes under the same package as of Main class of #SpringBootApplication, got recognised with #Component because #SpringBootApplication defines an automatic #ComponentScan on the package.
So other classes which were defined in some other package are not recognised because there is no #ComponentScan for those classes' package.
You can do the following to get those classes recognised(add the other packages which are not directly under the hierarchy of #SpringBootApplication):
#ComponentScan({"com.example.springboot.anything","com.example.springboot.somethingelse"})
#SpringBootApplication
public class AnySpringBootApplication {
I am sure it will not be a common case, but for me the problem was that my class had a relatively generic name. Although it was located in the package mentioned in the ComponentScan, on the same level with other classes all found and used, I kept having problems that the ApplicationContext failed to load. After I renamed the class it worked, I found that two other classes in org.springframework had the same name.

How to work with spring annotations in large applications?

If you are starting a Spring project, you may know where you have placed the #controller, #requestmapping annotations and other annotations and the corresponding controller class.
Lets say few months down the line a new developer comes into your team, how would he figure out which classes to work with? Because unlike the xml based approach where all the configurations is centrally located in an config.xml file, we don't have nothing of that sort with annotation as per my knowledge (I am new to spring), we write the respective annotations in a class itself.
In Spring, two ways to define your configuration :
Either in a XML file or
Java class
So just like xml, in Java also you need to create a configuration class which will have all the required configurations details. You can define all of your beans, filters etc here.
For example , You create a configuration class MvcConfig with the below annotations
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
#ComponentScan(basePackages = {"com.abc.example"})
Now your base package is com.abc.example. In all the applications, the best practice is to keep all of you controller\service\DAO classes in specific packages like
Controller : com.abc.example.controller,
Service : com.abc.example.service,
DAO : com.abc.example.dao
So anybody who comes in will know where are all the respective classes located and from where to start.
Example configuration class :
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
#ComponentScan(basePackages = {"com.abc.example"})
public class MvcConfig extends WebMvcConfigurerAdapter

spring java configuration unit test

I am trying out spring's java configuration. While using xml config files my unit tests use to have the following
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(....)
If I am using java configuration, How do i do it. or should I just use
ApplicationContext appConfig = new AnnotationConfigApplicationContext(SimpleConfiguration.class);
As of Spring 3.1, #ContextConfiguration now has full support for #Configuration classes; no XML required.
See http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#d0e1392
Or more specifically, http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#testcontext-ctx-management-javaconfig, which shows the following code snippet:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from AppConfig and TestConfig
#ContextConfiguration(classes={AppConfig.class, TestConfig.class})
public class MyTest {
// class body...
}
AppConfig and TestConfig are #Configuration classes (aka "Java config" classes in #user373201's comments)
#ContextConfiguration is used to load the Spring configurations while you are working with test cases . If you don't need it , you could use ClassPathXmlApplicationContext to load the Spring configuration .
Use the constructor which takes in configuration locations as String array .
AnnotationConfigApplicationContext is used to auto detect the annotated classes . I don't think it can be used to load configuration files . It is similar to context:component-scan
SpringJUnit4ClassRunner provides Spring Test support for Junit via annotations like #Test.

Resources