I'm fairly new to Spring and my understanding is a bit scratchy so bear with me and word answers for an idiot.
I've started working on a relatively large, maven based project which has a load of (xml) spring configuration. For this we have a bunch of JUnit tests. At the moment spring configuration for the tests replaces the configuration for the core project modules, which is an issue because it means that if we make changes to the configuration of the main project then those changes aren't reflected in the test module and hence it's possible to get funny test results.
We are currently changing this structure so that the test module configuration overrides (rather than replaces) the main modules configuration. So we only have to override the particular beans we are interested in for each tests.
Is this the best way to do this? Are there alternative ways? Is it possible to fine tune this ever further so that you can override specific setters of a particular bean (rather than the entire bean) for tests?
Any advice is much appreciated.
You can split your main configuration in separate (logical) units and import them into your test configuration as needed.
Keep in mind that Spring 3.1 will introduce XML profiles. This is perfect for testing (with different enviroment specific configurations). It's not finally released yet but I would (and do) use the milestone in new projects.
Ow having to mess with the method to test it is a bit weird by it self in my opinion.
I would avoid that at all if possible, and use spring resources to help you, with dependency injection, different application-contexts for test and dev and mock frameworks you can test almost every thing I can think of.
Maybe you could try to use those.
An example, it's a bit hard to simulate an user security context, but with spring it becomes fairly easy, you just need to create an application-context.xml for the tests (and point to it) and assign a factory in it to create a Bean of Authentication type(it's an interface) and you can use easy mock to automate this bean responses.
But for that to work you have to build your code with that in mind so instead of calling SecurityContext.getContext.... you inject that Authentication Bean from the factory.
In your main configuration separate out all the environment dependent configuration (like datasource, jms connectionfactory etc) to a separate config file - (something like infrastructure-config.xml). The configuration that doesn't change across test & deploy goes into a different file - application-config.xml.
Now for the test only create a new version of the infrastructure config file - test-infrastructure-config.xml and use it with the application-config from the main.
Related
I want to know how to discover all qualifying beans that should be implemented when using some component together Spring.
For example, when using JPA and Spring Boot we need beans as like as sessionFactory and dataSource (Any more? I don't know, see It?).
Is there any official place where I can check the pre requisite list of beans?
I've made many searches through the official schemas and I couldn't find a pattern for bean dependencies.
After some time I've come into some steps that helped me and maybe help others. I'm answering this also because there are a lot of material related to Beans in XML files and in a Maven project, but if you try to create a XML free project, things become more rare when using Spring.
Notice: in deep Spring doesn't cares if the bean is an annotation or inside a XML. I preferred these configurations as a personal choice.
Some project details:
Gradle (project configurations are in application.properties file)
Java 8
Bean class(es) for src and for test. Note: You can use extends among them.
In case of doubt, https://start.spring.io/ an awesome way to create from nothing a spring project with your dependencies. Gradle format dependencies usually can be found at maven repository nearby the maven format.
Resolution:
Create a unit test (e.g JUnit) to just test your layer. For example mine was persistence layer.
Be careful to add each framework(that is going to be loaded by Spring) at once. Dealing with many unconfigured frameworks at same time would lead to caos since may be hard to figure out from where the Bean class should come from.
When the test fails look at his bottom of your console. Some exception will be thrown saying that a Bean with some name is missing. This are the guys you need.
Create a method typed with #Bean inside a class typed with #Configuration. This method must returns variable/object type complained in the exception message. Additional annotations maybe be required, for example, #EnableTransactionManagement for JPA beans.
Bonus:
Spring is deeply connected to IoC (dependency injection) and containers. Take a look at this contents because when you see that you realizes why to use Beans.
I'm working on an application where we use integration tests intensively since a core framework we are using operates on the database.
I have test classes using configuration context class such as this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ConfigA.class)
public A_Test(){
}
The majority of tests are using same context like above. We have over 200+ such tests. But recently we needed some additional configuration for some use cases as well, like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ConfigA.class, ConfigB.class})
public B_Test(){
}
Problem is now when we execute all tests with maven, or IDE runners , loaded cache for ConfigA no longer works. Spring tries to recreate a context for ConfigA which fails because we have H2 DB already configured and Spring tries to create schemas, tables which fails to do so.
To overcome we started to use #DirtiesContext on all tests. Result is over 1H build time, which reduces the developer productivity significantly.
Question: is it possible to clear context for tests like B_Test only? #DirtiesContext(ClassMode=AFTER_CLASS) doesn't help because order of the tests are not guaranteed(and really we don't want to go that way). It fails when type of B_Test tests are last to run. Same for #DirtiesContext(ClassMode=BEFORE_CLASS) visa versa
Is it possible to simulate #DirtiesContext(ClassMode=AFTER_CLASS) and #DirtiesContext(ClassMode=BEFORE_CLASS) at the same time on a bunch of tests?
Or is there any other way to solve in general this problem?
What we tried so far:
Junit Suites : didn't help anything with spring context
ContextHierarchies : didn't help with the case that B_Type tests also dirties the context
Test Ordering: well nobody is really happy about refactoring all the tests to make it work magically
How about using both #DirtiesContext(ClassMode=AFTER_CLASS) and #DirtiesContext(MethodMode=BEFORE_METHOD)?
When you do that, Spring will reload context ConfigA.class and ConfigB.class just before invoking test methods annotated with #DirtiesContext(MethodMode=BEFORE_METHOD).
And then, after all tests of B_Test finished, Spring shutdowns the contexts (and next test class with SpringJUnit4ClassRunner will load its context).
This is essentially a duplicate of Make Spring Boot Recreate Test Databases.
In summary, you likely only need to ensure that you are using unique names for each embedded database that is created using your ConfigA class.
Please read my comments here for details: https://stackoverflow.com/a/28867247/388980
Also, see the comments in SPR-8849 for further details.
Regards,
Sam (author of the Spring TestContext Framework)
I have a Spring-enabled JUnit Test. It loads my default applicationContext.
Now I want to replace a single bean for my test, i.e. entityManager with testEntityManager.
I can imagine three possible ways, which don't seem very elegant:
split the context (defaultContext, emContext) and override context file by test context file (emContext in test resources)
use factory and choose testEntityManager (in production code)
not to use Spring, but build the object hierarchy myself (least feasible solution)
Is there a best practice how to do it right?
Background to this question is: I really only want to replace the objects close at the boundary (DB, Webservices, etc)
Yours Sincerely
EDIT: I have solved it this way now:
I added a properties file to my classpath and test classpath and used a Spring alias in conjunction with a property placeholder.
This way I was able to wire my beans to a different implementation in the tests.
Spring allows you to override bean definitions, when you are loading contexts from multiple locations.
So you don't necessarily need to to split the context "/applicationContext.xml".
Instead have an additional application context for test "/applicationContext-test.xml", where you override the bean you need.
Then pull in both configurations and have the bean in the test configuration override the bean in the production configuration.
#ContextConfiguration({"/applicationContext.xml", "/applicationContext-test.xml"})
The best practise IMHO would be to use spring bean definition profiles. My documentation link will lead you to other readable resources. Google will also provide useful links like Gordon Dickens: Spring 3.1 Environment Profiles.
I'm building an application using OpenJPA 2.0.0, Jersey 1.3, and JUnit 4.8.1.
I've set it up so I have two different persistence units defined in my persistence.xml: "default" and "unittest." Default is set up to connect to an Oracle instance, while unittest is set up to connect to a local H2DB embedded database file. I do this so that I always start my unit tests with a clean database which has certain known data in it, which can be overwritten between each run of the unit tests.
The problem is that now I want to use the Jersey Testing Framework to test my actual webservices, rather than just the lower layers of the program. My root resource classes don't load the unittest persistence unit, they always load the default.
So what I probably need to do is to inject into the root resource classes which persistence unit should be used to instantiate the EntityManager, and then have some way to inject unittest when I'm running my tests but inject default otherwise. But I can't think of any good way to do that.
I'm brand new to Java EE development, which might be obvious.
Any help?
I think it should be possible to create a second persistence.xml in src/test/resources/META-INF.
If I understand things correctly, maven will put target/test-classes in the classpath ahead of target/classes, so that in a unit test, only your test persistence.xml will be read. That way you can use the same persistence unit name, but with a different configuration.
src/main/resources/
META-INF
persistence.xml <-- for actual application
src/test/resources/
META-INF
persistence.xml <-- for unit tests
EDIT:
oops, I was tricked into believing you used maven by the other answer. If you are not, forget what I said...
Are you using Maven ?
If yes, there is a trick that allows you to "read" a POM value in your Java class.
It was very useful for me, you would just have to set your Persistence Unit Name in your POM, a different one during the test, and that's it.
Maven variables in java context
I'm working on a Spring MVC project, and I have unit tests for all of the various components in the source tree.
For example, if I have a controller HomeController, which needs to have a LoginService injected into it, then in my unit test HomeControllerTest I simply instantiate the object as normal (outside of Spring) and inject the property:
protected void setUp() throws Exception {
super.setUp();
//...
controller = new HomeController();
controller.setLoginService( new SimpleLoginService() );
//...
}
This works great for testing each component as an isolated unit - except now that I have a few dozen classes in the project, after writing a class and writing a successful unit test for it, I keep forgetting to update my Spring MVC context file that does the actual wiring-up in the deployed application. I find out that I forgot to update the context file when I deploy the project to Tomcat and find a bunch of NullPointers from non-wired-up beans.
So, here are my questions:
This is my first Spring project - is it normal to create unit tests for the individual beans, as I have done, and then create a second suite of tests (integration tests) to test that everything works as expected with the actual application context? Is there an established best practice for this?
In addition, how do you separate the unit tests from the integration tests? I have all of the source code in src, the unit tests in test - should there be a 2nd test folder (such as test-integration) for integration test cases?
Since this is my first Spring project, I'm curious how others usually go about doing this sort of thing - and rather than re-invent the wheel I rather ask the rest of the community.
I can't speak to being a best practice, but here's what I've done in the past.
Unit tests:
Create unit tests for non-trivial beans (ie, most of your Spring related beans)
Use Mocks for injected services where practical (ie, most if not all the time).
Use a standard naming convention for these tests in the project test directory. Using Test or TestCase as a prefix or suffix to the classname seems to be widely practiced.
Integration Tests:
Create an AbstractIntegrationTestCase that sets up a Spring WebApplicationContext for use in intetgration test clases.
Use a naming convention for integration tests in the test directory. I've used IntTest or IntegrationTest as a prefix or suffix for these tests.
Set up three Ant test targets:
test-all (or whatever you want to name it): Run Unit and Integration Tests
test: Run Unit tests (just because test seems to be the most common usage for unit testing
test-integration: run the integration tests.
As noted, you can use the naming conventions that make sense for your project.
As to separating unit from integration tests into a separate directory, I don't think it matters as long as the developers and their tools can find and execute them easily.
As an example, the last Java project I worked on with Spring used exactly what is described above, with integration tests and unit tests living in the same test directory. Grails projects, on the other hand, explicitly separate unit and integration test directories under a general test directory.
A few isolated points:
Yes, it's a common approach to Spring testing - seperate unit tests and integration tests where the former doesn't load any Spring context.
For your unit tests, maybe consider mocking to ensure that your tests are focussed on one isolated module.
If you're tests are wiring in a ton of dependencies then they aren't really unit tests. They're integration tests where you are wiring of dependencies using new rather than dependency injection. A waste of time and duplicated effort when your production application uses Spring!
Basic integration tests to bring up your Spring contexts are useful.
The #required annotation may help you to ensure you catch required dependencies in your Spring wiring.
Maybe look into Maven which will give you explicit phases to bind your unit and integration tests on to. Maven is quite widely used in the Spring community.
A lot of the tedious double-book-keeping with spring goes away if you also switch to a purely annotated regime, where you annotate all your beans with #Component, #Controller, #Service and #Repository. Just add #Autowired to the attributes you need to get injected.
See section 3.11 of the spring reference manual. http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config
On a related note, we have been using the division Unit/Integratrion tests that KenG describe. In my most recent regime we have also introduced a third "class" of tests, "ComponentTests". These run with full spring wiring, but with wired stub implementations (using component-scan filters and annotations in spring).
The reason we did this was because for some of the "service" layer you end up with an horrendous amount of hand-coded wiring logic to manually wire up the bean, and sometimes ridiculous amounts of mock-objects. 100 lines of wiring for 5 lines of test is not uncommon. The component tests alleviate this problem.
Use the InitializingBean interface (implements a method "afterPropertiesSet") or specify an init-method for your beans. InitializingBean is typically easier because you don't need to remember to add the init method to your beans.
Use afterPropertiesSet to ensure everything is injected as non-null, if it is null, throw an Exception.
When I've created integration tests for web applications, I've put them in a separate directory. They are built using jUnit or TestNG and interact with the system under test using something like Selenium that hits the web pages as if they were users. The cycle would go like this: compile, run unit tests, build the web app, deploy it to a running server, execute the tests, undeploy the app, and report results. The idea is to test the whole system.
With regard to running unit tests separately from integration tests, I put all the latter into an integration-test directory and run them using IDE/Ant using an approach like this. Works for me.
the difference between unit test and integration test is , unit test does not necessarily load your context, you are focusing on the code which you have written - it works fails fast , that is with and without exceptions, by mocking any depends calls in it.
But in case of integration tests , you load context and perform end to end test like actual scenarios.