We are using Spring for my application purposes, and Spring Testing framework for unit tests. We have a small problem though: the application code loads a Spring application context from a list of locations (XML files) in the classpath. But when we run our unit tests, we want some of the Spring beans to be mocks instead of full-fledged implementation classes. Moreover, for some unit tests we want some beans to become mocks, while for other unit tests we want other beans to become mocks, as we are testing different layers of the application.
All this means I want to redefine specific beans of the application context and refresh the context when desired. While doing this, I want to redefine only a small portion of the beans located in one (or several) original XML beans definition file. I cannot find an easy way to do it. It's always regarded that Spring is a unit-testing-friendly framework, so I must be missing something here.
Do you have any ideas how to do it?
Thanks!
I would propose a custom TestClass and some easy rules for the locations of the spring bean.xml:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath*:spring/*.xml",
"classpath*:spring/persistence/*.xml",
"classpath*:spring/mock/*.xml"})
#Transactional
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
public abstract class AbstractHibernateTests implements ApplicationContextAware {
/**
* Logger for Subclasses.
*/
protected final Logger log = LoggerFactory.getLogger(getClass());
/**
* The {#link ApplicationContext} that was injected into this test instance
* via {#link #setApplicationContext(ApplicationContext)}.
*/
protected ApplicationContext applicationContext;
/**
* Set the {#link ApplicationContext} to be used by this test instance,
* provided via {#link ApplicationContextAware} semantics.
*/
#Override
public final void setApplicationContext(
final ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
If there are mock-bean.xml in the specified location, they will override all "real" bean.xml files in the "normal" locations - your normal locations might differ.
But … I would never mix mock and non-mock beans, as it's hard to trace problems when the application grows older.
One of the reasons spring is described as test-friendly is because it may be easy to just new or mock stuff in the unit test.
Alternately we have used the following setup with great success, and I think it is quite close to what you want, I would strongly recommend it:
For all beans that need different implementations in different contexts, switch to annotation based wiring. You can leave the others as-is.
Implement the following set of annotations
<context:component-scan base-package="com.foobar">
<context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>
<context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
Then you annotate your live implementations with #Repository, your stub implementations with #StubRepository, any code that should be present in the unit-test fixture ONLY with #TestScopedComponent. You may run into needing a couple more annotations, but these are a great start.
If you have a lot of spring.xml, you will probably need to make a few new spring xml files that basically only contain the component-scan definitions. You'd normally just append these files to your regular #ContextConfiguration list. The reason for this is because you frequently end up with different configurations of the context-scans (trust me, you will make at least 1 more annotations if you're doing web-tests, which makes for 4 relevant combinations)
Then you basically use the
#ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
Note that this setup does not allow you to have alternating combinations of stub/live data. We tried this, and I think that resulted in a mess I wouldn't recommend anyone ;) We either wire inn the full set of stubs or the full set of live services.
We mainly use auto-wired stub dependencies when testing gui near stuff where the dependencies are usually quite substantial. In cleaner areas of the code we use more regular unit-testing.
In our system we have the following xml-files for component-scan:
for regular web production
for starting web with stubs only
for integration tests (in junit)
for unit tests (in junit)
for selenium web tests (in junit)
This means we totally have 5 different system-wide configurations that we can start the application with. Since we only use annotations, spring is fast enough to autowire even those unit tests we want wired. I know this is untraditional, but it's really great.
Out integration tests run with full live setup, and once or twice I have decided to get really pragmatic and want to have a 5 live wirings and a single mock:
public class HybridTest {
#Autowired
MyTestSubject myTestSubject;
#Test
public void testWith5LiveServicesAndOneMock(){
MyServiceLive service = myTestSubject.getMyService();
try {
MyService mock = EasyMock.create(...)
myTestSubject.setMyService( mock);
.. do funky test with lots of live but one mock object
} finally {
myTestSubject.setMyService( service);
}
}
}
I know the test purists are going to be all over me for this. But sometimes it's just a very pragmatic solution that turns out to be very elegant when the alternative would be really really ugly. Again it's usually in those gui-near areas.
See this tutorial with #InjectedMock annotation
It saved me a lot of time. You just use
#Mock
SomeClass mockedSomeClass
#InjectMock
ClassUsingSomeClass service
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
and all your problems are solved. Mockito will replace the spring dependency injection with a mock. I just used it myself and it works great.
There are some very complicated and powerful solutions listed here.
But there is a FAR, FAR simpler way to accomplish what Stas has asked, which doesn't involve modifying anything other than one line of code in the test method. It works for unit tests and Spring integration tests alike, for autowired dependencies, private and protected fields.
Here it is:
junitx.util.PrivateAccessor.setField(testSubject, "fieldName", mockObject);
You can also write your unit tests to not require any lookups at all:
#ContextConfiguration(locations = { "classpath:/path/to/test-config.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class MyBeanTest {
#Autowired
private MyBean myBean; // the component under test
#Test
public void testMyBean() {
...
}
}
This gives an easy way to mix and match real config files with test config files.
For example, when using hibernate, I might have my sessionFactory bean in one config file (to be used in both the tests and the main app), and have by dataSource bean in another config file (one might use a DriverManagerDataSource to an in-memory db, the other might use a JNDI-lookup).
But, definitely take heed of #cletus's warning ;-)
Easy. You use a custom application context for your unit tests, or you don't use one at all and you manually create and inject your beans.
It sounds to me like your testing might be a bit too broad. Unit testing is about testing, well, units. A Spring bean is a pretty good example of a unit. You shouldn't need an entire application context for that. I find that if your unit testing is so high-level that you need hundreds of beans, database connections etc., you have a really fragile unit test that is going to break on the very next change, will be hard to maintain and really isn't adding a lot of value.
You can use the import feature in your test app context to load in the prod beans and override the ones you want. For example, my prod data source is usually acquired via JNDI lookup, but when I test I use a DriverManager data source so I don't have to start the app server to test.
I don't have the reputation points to pile on duffymo's answer, but I just wanted to chime in and say his was the "right" answer for me.
Instantiate a FileSystemXmlApplicationContext in your unit test's setup with a custom applicationContext.xml. In that custom xml, at the top, do an as duffymo indicates. Then declare your mock beans, non-JNDI data sources, etc, that will override the id's declared in the import.
Worked like a dream for me.
You do not need to use any test contexts (doesn't matter is XML or Java based). Since Spring boot 1.4 there is available new annotation #MockBean which introduced native support for mocking and Spying of Spring Beans.
Perhaps you could use qualifiers for your beans? You would redefine the beans you want to mock up in a separate application context and label them with a qualifier "test". In your unit tests, when wiring your beans always specify the qualifier "test" to use the mock ups.
I want to do the same thing, and we're finding it essential.
The current mechanism we use is fairly manual but it works.
Say for instance, you wish to mock out bean of type Y. What we do is every bean that has that dependency we make implement an interface - "IHasY". This interface is
interface IHasY {
public void setY(Y y);
}
Then in our test we call the util method...
public static void insertMock(Y y) {
Map invokers = BeanFactory.getInstance().getFactory("core").getBeansOfType(IHasY.class);
for (Iterator iterator = invokers.values().iterator(); iterator.hasNext();) {
IHasY invoker = (IHasY) iterator.next();
invoker.setY(y);
}
}
I do not want to create a whole xml file just to inject this new dependency and that is why I like this.
If you're willing to create an xml config file then the way to go would be to create a new factory with the mock beans and make your default factory a parent of this factory. Make sure then that you load all your beans from the new child factory. When doing this the sub-factory will override the beans in the parent factory when the bean id's are the same.
Now if, in my test, If I could programmatically create a factory, that would be awesome. Having to use xml is just too cumbersome. I'm looking to create that child factory with code. Then each test can configure its factory the way it wants. There's no reason why a factory like that won't work.
spring-reinject is designed to substitute beans with mocks.
Since the OP this has come along: Springockito
Related
I am wondering what is the current best practice as to the use of factory pattern within the context of Spring framework in using dependency injection. My wonder arises about whether the factory pattern is still relevant nowadays in light of the use of Spring dependency injection. I did some searching and see some past discussion (Dependency Injection vs Factory Pattern) but seem there is different view.
I see in some real life project in using a Map to hold all the beans and rely on autowiring to create those beans. When the bean is needed, it get it via the map using the key.
public abstract class Service {
//some methods
}
#Component
public class serviceA extends Service {
//implementation
}
#Component
public class serviceB extends Service {
//implementation
}
Map<String, Service> services;
But I see there is some difference among the two approaches.
Using the above method, all beans are created on application start up and the creation of object is handled by the framework. It also implies there is only one bean for each type.
While for factory pattern, the factory class creates the object on request. And it can create a new object for each request.
I think a deeper question may be, when Spring framework is used in a project, should it be strived to not create any object inside a class, which means the factory pattern ( or any creational design patterns?) should not be used, as Spring is supposed to be the central handler of the objects dependency ?
The answer to this question can be really deep and broad, I'll try to provide some points that hopefully will help.
First off, spring stores its beans (singletons) in the ApplicationContext. Essentially this is the map you're talking about. In a nutshell, it allows getting the bean by name, type, etc.
ApplicationContext, while being a really important concept, is not the whole Spring, in fact Spring framework allows much more flexibility:
You say, using a map implies that all the beans will be created at the beginning of the application and there is one instance of the bean.
Spring has a concept of Lazy beans, basically supporting a concept of beans being actually created only when they're required for the first time, so Spring supports the "delayed" beans initialization
Spring also allows more than one instance of a bean per type. So this map is more "advanced". For example you can create more than one implementation of the interface and use declare both as beans. As long as you provide enough information about what bean should be injected to the class that might use them (for example with a help of qualifiers suppored in spring), you're good to go. In addition, there are features in spring IoC container that allow injecting all registered implementations of an interface into a list:
interface Foo {}
#Component
class FooImpl1 implements Foo {}
#Component
class FooImpl2 implements Foo {}
class Client {
#Autowired
List<Foo> allFoos;
}
Now you say:
While for factory pattern, the factory class creates the object on request. And it can create a new object for each request.
Actually Spring can create objects per request. Not all beans have to be singletons, in general spring has a concept of scopes for this purposes.
For example, scope prototype means that Spring will create a bean upon each usage. In particular one interesting usage that spring supports in variety of ways is Injecting prototype bean into singleton. Some solutions use exactly like a factory (read about annotation #Lookup others rely on auto-generated proxy in runtime (like javax.inject.Provider). Prototype scope beans are not held in the application context, so here again spring goes beyond a simple map abstraction.
Last feature that you haven't mentioned is that sometimes even for singletons the initialization can be a little bit more complicated then calling a constructor with Parameters. Spring can address that by using Java Configurations:
#Configuration
public class MyConfig {
public SomeComplicatedObject foo(#Value("...") config, Bar bar) {
SomeComplicatedObject obj = new SomeComplicatedObject() // lets pretend this object is from some thirdparty, it only has no-op constructor, and you can't place spring annotations on it (basically you can't change it):
obj.setConfig(config);
obj.setBar(bar);
return obj;
}
}
The method foo here initializes the object SomeComplicatedObject and returns it. This can be used instead of factories to integrate "legacy" code (well, java configurations go way beyond this, but its out of scope for this question).
So bottom line, you Spring as an IoC container can provide many different ways to deal with object creation, in particular it can do everything that factory design pattern offers.
Now, I would like to also refer to your last sentense:
I think a deeper question may be, when Spring framework is used in a project, should it be strived to not create any object inside a class, which means the factory pattern ( or any creational design patterns?) should not be used, as Spring is supposed to be the central handler of the objects dependency ?
Indeed you don't have to use Factory Pattern when using Spring, since (as I hopefully have convinced you) provides everything that factory can do and more.
Also I agree that spring is supposed to be the central handler of the objects dependency (unless there are also parts of the application which are written in a different manner so you have to support both :) )
I don't think we should avoid using "new" altogether, not everything should/can be a bean, but I do see (from my subjective experience, so this is arguable) that you use it much less leaving the creation of most of the objects to Spring.
Should we avoid a usage of any creation design pattern? I don't think so, sometimes you can opt for implementing "builder" design pattern for example, its also a creational pattern but spring doesn't provide a similar abstraction.
I think if your project uses Spring framework you should use it. Although it depends on your project design e.g. You may use creational patterns along side with Spring IoC. e.g when you have abstraction layers not framework dependant (agnostic code)
interface ServiceFactory {
Service create(String type);
}
#Component
class SpringServiceFactory implements ServiceFactory {
#Autowired private ApplicationContext context;
Service create(String type) {
return context.getBean(type)
}
}
I use Factory pattern as well when I refactor legacy not unit testable code which also uses Spring Framework in order to implement unit tests.
// legacy service impossible to mock
class LegacyApiClient implements Closeable {...}
#Component
class LegacyApiClientFactory {
LegacyApiClient create(String endpoint) {
return new LegacyApiClient(endpoint);
}
}
#Component
class OtherService {
private final String endpoint
private final LegacyApiClientFactory factory;
OtherService(#Value("${post.endpoint}") String endpoint,
LegacyApiClientFactory factory) {...}
void doCall {
try (LegacyApiClient client = factory.create(endpoint)) {
client.postSomething();
}
}
}
....
// a random unit test
LegacyApiClient client = mock(LegacyApiClient.class)
LegacyApiClientFactory factory = mock(LegacyApiClientFactory.class)
OtherService service = new OtherService("http://scxsc", factory);
when(factory.create(any())).thenReturn(client)
service.doCall()
....
I have many different SpringBoot tests running. So far the auto configuration slices were really helpful, especially in combination with #MockBean.
But in my current test no such slice fits and booting up the complete context using #SpringBootTest is too slow.
Is there a way to manually set the tip of the object tree to be started with and from there spring autowires all needed beans? Or is there a way to set all needed beans manually?
In my specific case i want to test a MapStruct generated mapper (using componentModel = "spring") this mapper uses two other mappers, each injecting a service to do their work.
The services are provided via #MockBean:
#RunWith(SpringRunner.class)
#SpringBootTest
public class ProductResponsibleUnitMapperTest {
#Autowired
private PRUMapper mapper;
#MockBean
private TradingPartnerService tradingPartnerService;
#MockBean
private ProductHierarchyService productHierarchyService;
#Test
public void mapForthAndBack(){
//works but takes ages to boot
}
}
I could not use constructor injection on the mappers (for the services) because MapStruct won't generate correct implementations.
How to get a Spring-Context only containing the needed beans?
I found one way by explicitly declaring all implementation used:
#SpringBootTest(classes = {ProductResponsibleUnitMapperImpl.class, LegalEntityMapperImpl.class, ProductHierarchyMapperImpl.class})
For more complex setups it will be cumbersome and also dangerous to declare generated classes.
I am still searching for a better cleaner way to let Spring decide what classes needed. It should be possible to set the class in hand and let Spring decide what classes needed and to be instantiated.
Please consider following situation with spring 4.0.7
For Eclipselink, we use a load-time-weaver. So we wanted to experiment with Springs #Configurable annotation using #EnableSpringConfigured with #EnableLoadTimeWeaving at the same time.
This is fully functional, and Spring-Beans are injected perfectly into POJOs during construction. This functionality is helpful for us, because we want to keep some code regarding validation of these POJOs inside these and not somewhere else in a Bean.
SOme of our Spring Context contains Beans that do not implement any interface, because they are local to some package and used only there. Lets say, FooLogicBean is one of them. If this is to be injected into another Bean, and some Spring-AOP-Aspect (not-aspectj) like some performance measurement aspect is in the execution path, Spring will create a CGLIB autoproxy for the FooLogicBean and inject that. This is fully functional and works perfectly too.
Problems arise, when we want to actually use a POJO that is annotated with #Configurable as a parameter in a method of FooLogicBean (like fooLogicBean.doValidate(myPojo); ), respectively a CGLIB Proxy. In this case, some non-trivial magic stops that POJO from being woven thru aspectj (AnnotationBeanConfigurerAspect from spring-aspects). It is even never woven anywhere in the code regardless of calling the aforementioned doValidate() Method.
If we create that POJO inside FooLogicBean, but dont use it as a method Parameter, it gets woven again due to #Configurable.
Without knowing the Autoproxy creation code, we assume some fancy marking routine from hindering a class from being detected by aspectj, if that class was already used in spring-aop. use in this case means Access.
Did anyone experiment with such obscure constellation and knows a solution for that?
Thanks in advance!
Proxies are created by subclassing, i.e. when you create a proxy of an annotated class Foo:
class Foo {
#Bar
void bar() { }
}
the proxy is created by implementing a class
class Foo$Proxy extends Foo {
#Override
void bar() {
// Proxy logic
}
// Overridden methods of Object
}
This makes the Foo$Proxy class a valid Liskov substitute for Foo. However, normal override semantics apply, i.e. non-inherited annotations such as #Bar are not longer present for the overridden methods. Once another annotation-based API processes your beans, all annotations have disappeared which leads to your outcome. This is true for all kinds of annotations. Those on types, methods and method parameters.
But is it avoidable? It most certainly is by using a proxy generator that was written recently and is built with knowledge of what annotations are, something that is not true for cglib which was first shipped in the early days of the Java virtual machine. However, as long as Spring does not move away from cglib, you will have to live with today's limitations.
I have seen developers using Spring's #Autowired feature making Spring framework responsible for instantiating and injecting SUT (System Under Test) or CUT (Class Under Test) in the test class or fixture. The following is the snippet showing #Autowired being used in the test fixture:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.ExpectedException;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.test.context.ContextConfiguration;
interface BackingStore
{
//Some methods
}
class Logger
{
public Logger(BackingStore backingStore)
{
//Capture input parameter into member variables
}
public void Log(String message)
{
//Some logic
}
}
#ContextConfiguration(locations = { "classpath:someconfig.xml" })
public class LoggerTests extends AbstractTestNGSpringContextTests
{
#Autowired
private Logger _logger;
#Test
#ExpectedException(NullPointerException)
public void Log_WhenPassedNull_ShouldThrowException()
{
_logger.Log(null);
}
}
All the dependencies (recursively) required by the SUT are specified as part of the Spring configuration XML file. I do not like this approach. I like all the test (unit or integration) to read like a story (I heard Kent Beck saying the same thing :)). I like instantiating SUT/CUT in the test case itself even though if it is complex. This gives a clear picture about the test case.
I have few concerns regarding #Autowired or any auto injection mechanism being used for injecting SUT in the test fixture:
It reduces test code readability. #Autowire appears like magic. Arrange of AAA (Arrange-Act-Assert) moves to XML file from test code.
It reduces test code maintainability. This is because of #2.
Could not effectively verify constructor of SUT/CUT throwing exception in exceptional cases. I am not 100% sure about this. I do not know if Spring framework has an answer for this.
It seems overkill for unit or integration tests.
I ask experts for 2 cents on this subject.
Thanks.
It only reduces test code readability if you dont know where to look for the #Autowired objects. I would advise using SpringJunitTestRunner that defines the test application context at the top of the unit test class.
Using dependency injection in your test cases allows you to easily test with different objects.
E.g. If your code required a 3rd party service, you could use dependency injection (e.g. Autowiring a Spring bean) to inject a mocked service for your unit tests and the real service for the application.
So for this reason it definitley doesnt decrease the test code maintainability, as it is really encouraging loose coupling between the code youre testing and any external objects.
It may be overkill to inject all objects in such a way, but it is definitely not overkill for unit tests/integration tests in general.
If I am using spring frame work in my application does creating an object like this Test test = new Test() a bad way for creating an instance? Should I always use the bean config to get the objects/bean that I need? If yes, does that means I should have all the object/bean definition in spring applicationContext xml file?
If you want your object to be managed by Spring (this means that dependencies are injected, among other things) you have to use the ApplicationContext.
Calling Test test = new Test() isn't illegal, or even bad practice. It just means that Spring will have no awareness of this object, and it won't bother autowiring it's dependencies, or doing anything else that you'd expect Spring to do.
You don't necessarily need to use the applicationContext.xml file for ALL of your bean declarations. Many people favor annotations, which allow you to declare beans outside of the applicationContext.xml file.
It's worth nothing that Spring-managed beans are by default singletons (think of Servlets). If you want stateful beans that are Spring aware, you could use an ObjectFactoryCreatingFactoryBean to do something like this:
#Autowired
private ObjectFactory myWidgetFactory;
public void doStuff() {
Widget w = myWidgetFactory.getObject();
}
You can read more about this behaviour here:
http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.html
For me there's a big difference between objects that represent components of my application -- services, controllers, DAOs, utilities, etc. -- and objects that represent entities within my application -- Person, Order, Invoice, Account, etc. The former type of objects should absolutely be managed by Spring and injected. The latter type are typically created on the fly by the application, and that frequently will involve calling new. This is not a problem.
Test test = new Test() a bad way for
creating an instance?
Yes it is bad practice.
Should I always use the bean config
to get the objects/bean that I need?
Yes, if you are using Spring for dependency injection.
If yes, does that means I should have
all the object/bean definition in
spring applicationContext xml file?
Always! You could use Annotations too.