When I setup Spring with XML a can override component definitions in XML files that are loaded later.
It's very usefull for tests - I create default config set and than load it with addition test configuration that replaces some of components with specials (stubs, mocks, and so on).
Now i start to migrate to annotation based configurations and it causes some problems.
The direct way to use annotations is auto-discovering of packages with #Component
So I have
#Configuration
#ComponentScan({"some.pack1", "some.pack2"})
public class ProductConfig{}
And when
#Configuration
#Import({ProductConfig.class})
#ComponentScan({"test.pack"})
public class TestConfig{}
But it will cause conflict if I try to override components in test.pack
And what I can do?
After some investigations where are 3 answers with some issues on them
Worst - i can use #Filter on ComponentScan - it's worst way,
i must not import existed config (that can has some additional beans)
i must rescan all components, and explicitly define set of filters
i can use #Profile and activeProfiles - it's better, while it's more sophistical, implict, but
it means that i must to know at product classes that they can be disabled in some tests
not to use #ComponentScan on override Config and using #Bean insted of it
it's maybe well on test configurations, but it means that I lost ability to use #Component annotation
use setParent on contexts - it works well, but
it's explicit operation on implementation of ApplicationContext not on interface
it's not hard to setup if overriding services has #Autwire dependency on some components from overriden config - require manual register and refresh
What is best and standard way to override conigurations??? When I used XML-based it was not a problem...
#profile plays a crucial role while implementing the testing strategy for your service/code.
For example, in development, you may have:
public interface DataSource{
public String getHost();
}
Default implementation is
#Component
#Profile("Prod")
public class DevDataSource implements DataSource {
public String getHost(){
// return actual value
}
And the implementation for component tests(Fake impl)
#Component
#Profile("test")
public class StubbyDataSource implements DataSource {
public String getHost(){
return "some-host"; // return mocked data
}
Now you can write a test here which can act as integration test, unit test and component tests (https://martinfowler.com/bliki/ComponentTest.html)
In that way, your testing strategy would be much more elegant, concise and easy to maintain. Just by changing the profile, the same test can point to different environments (real or fake).
Related
I have an interface like:
public interface DateTimeService {
ZonedDateTime now();
void fixTo(ZonedDateTime date);
void forget();
}
and I have two implementations of it. One for production where fixTo and forget throws exceptions and one for testing where we control time. Then I have a CDI config that depending on a flag instantiate the right type.
#ApplicationScoped
public class Configuration {
#Produces
#ApplicationScoped
public DateTimeService dateTimeService(Configuration config) {
if (config.isFakeDateTimeServiceEnabled()) {
return new FakeDateTimeService();
} else {
return new DefaultDateTimeService();
}
}
}
However, I wanted to remove fixTo and forget from DateTimeService as they are only there so we can control time in tests. I made a new interface like:
public interface FakeDateTimeService extends DateTimeService {
// fixto and forget is moved from DateTimeService to here
}
I have a few injection points. Some is in production code, some is in test code. In production code I would like to only be able to access DateTimeSerice, in test code I want be able to get a handle on the extended service.
In prod code:
#Inject
private DateTimeService dateTimeService;
In test code:
#Inject
private FakeDateTimeService dateTimeService;
If I leave the config unchanged, then the test code will never find my extended service (as CDI seems to ignore the run-time type of the instance produced by the producer method).
If I update the config to instantiate both (in this case I can even inject the genuine service into the fake one), then production cannot wire together as fake also implements the DateTimeService interface and it causes ambiguity. At this point I could probably just use a qualifier, but I neither want to change my production code because of this nor have to have a fake date time service exist in production context.
I tried to veto bean creation but I failed to do so.
What I thought would/should work is instantiate the right type and programmatically add it to the bean context but examples I found was for CDI 2.0 while for now, relevant part of my code is stuck on CDI 1.2.
Probably at this point you can tell, that I'm not a CDI expert. So I'm opened for suggestion on good CDI read materials as well as concrete suggestions on this problem.
Otherwise, I'm about to give up and just live with a DateTimeService that have fixTo and forget methods.
Depending on how you are doing it, you could use the following approaches, whereby some of them have already be mentioned in the comments.
With alternatives
For testing you provide an own beans.xml, which defines the alternative for testing, which replaces the production one. You will have to keep them in sync, whereby the test beans.xml contains changes necessary for testing. Depending on the CDI implementation the beans.xml can be left out and #Alternative will be enough.
https://docs.oracle.com/javaee/6/tutorial/doc/gjsdf.html
interface DateTimeService { ... }
// Active during production, beans.xml does not define alternative
class DefaultDateTimeService implements DateTimeService { ... }
// Active during test, beans.xml defines alternative
#Alternative
class FakeDateTimeService implements DateTimeService { ... }
// Injection point stays the same.
#Inject
DateTimeService dateTimeService;
// Used in test environment
<beans ... >
<alternatives>
<class>FakeDateTimeService</class>
</alternatives>
</beans>
With Arquillian
With Aarquillian you can assemble the deployment yourself and exclude the DefaultDateTimeService implementation and replace it with the FakeDateTimeService implementation. With this approach you don't need to hack anything because during test, only FakeDateTimeService implementation will be visible to the CDI container.
http://arquillian.org/guides/getting_started/
With CDI Extension
For testing you could provide an CDI extension and the FakeDateTimeService implementation in the test code, whereby the CDI Extension does veto the DefaultDateTimeService implementation.
package test.extension
public class VetoExtension implements Extension {
public <T> void disableBeans(#Observes ProcessAnnotatedType<T> pat) {
// type matching
if (DefaultDateTimeService.class.isAssignableFrom(pat.getAnnotatedType().getJavaClass())) {
pat.veto();
}
}
}
// Define SPI provider file, assuming test/resources is on CDI classpath
src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
// Single line you put in there
test.extension.VetoExtension
Deltaspike #Exclude
Deltaspike is a CDI extension library which provides some useful utilities for CDI development and testing, also a CDITestRunner is provided. The #Exclude annotation is used by an extension which does the same as the example above but already implemented for you.
https://deltaspike.apache.org/
https://deltaspike.apache.org/documentation/test-control.html
https://deltaspike.apache.org/documentation/projectstage.html
You should choose an approach which doesn't pollute your source code and forces you to hack to much to get it running for testing.
I would prefer Arquillian because here you have full control about what is in the deployment and nothing in your production code has to change or be specially implemented so its testable.
With Deltaspike you can exclude production code for testing and replace them with test implementations.
If no additional library or framework can be used I would prefer the alternative approach, because its the least complicated one to use.
I have a project which is expanding quickly and now has over a hundred components. For unit testing, I have a #Configuration class to substitute stubbed classes, such as a database service with limited functionality:
#Configuration
public class SpringDevTestConfiguration {
#Bean
#Profile("unittest")
public DatabaseService databaseService() {
// this one is needed for the test
return new TestDatabaseServiceImpl();
}
#Bean
#Profile("unittest")
public RobotControlService robotControlService() {
// Why should I do this on every service?
return new RobotControlServiceImpl();
}
... etc.
The vast majority of components don't need test alternatives, so we want the default one that exists and is picked up at runtime. But whenever a new component is added to the system, we have to add it to all of the #Configuration classes, or we get the "NoSuchBeanDefinitionException: No qualifying bean of type..." exception. That's a lot of boilerplate code to return Impl classes, and prevents us from making implementation classes package-protected (because the configuration class needs to be able to instantiate them).
I have tried adding #ComponentScan to the class, but that results in BeanDefinitionOverrideException. If I allow bean overrides with:
spring.main.allow-bean-definition-overriding=true
... then I get NoUniqueBeanDefinitionException because of the multiple database service implementations.
I'm sure I must be missing something. How can I have short, simple #Configuration class that only instantiates the test implementations I need for the test, then allows the other services to be discovered automatically without explicitly creating them?
I am developing a REST API with Spring Boot.The problem it's that I have one interface and two implementations and I want to test only with the mock implementation.
Interface CRMService
#Service
CRMServiceImpl
#Service
CRMServiceMock
Implementations: the first one is the real integration with the backend and the second is a mock for testing purposes, what's the best approach? Integration test or test based on the active profile ? If I need to autowire a service based on profile what's the best practice?
While I'm sure there's exceptions, generally it shouldn't be integration or unit tests (often involves mocks), but both; see testing pyramid concept.
Integration tests: just use the real service. If it calls out to other live services, then consider injecting the URLs as Spring Boot properties which point to mock servers in the test environment (Node.js or something easy and quick).
Unit tests: Consider using a test-framework like Mockito. Using this you can write your tests with mocks approximately like so:
private CRMServiceImpl mockService = mock(CRMServiceImpl.class);
#Test
public void someTest() {
when(mockService.someMethod(any(String.class), eq(5))).thenReturn("Hello from mock object.")
}
The above example roughly translates to "when some class invokes 'someMethod(String, int)' on your service, return the String specified".
This way allows you to still use mocks where necessary, but avoids having to maintain entire mock implementation profiles and avoids the problem of what to auto-wire.
Finally, if you need a full separate implementation, consider not auto-wiring services! Instead, use #Bean annotations in your configuration class and inject it via constructors into the classes that need it. Something like so:
#Configuration
public class ApplicationConfiguration {
#Value{$"service.crm.inmem"} // Injected property
private boolean inMem;
#Bean
CRMService getCRMService() {
if (inMem) {
return new CRMServiceMock();
}
return new CRMServiceImpl();
}
#Bean
OtherService getOtherService() {
// Inject CRMService interface into constructor instead of auto-wiring in OtherService.class
return new OtherService(getCRMService());
}
}
An example of when you could use ^^ would be if you wanted to switch between an in-memory store, and a real database-connection layer.
Personally I'd suggest doing dependency injection like the above example even when there aren't multiple implementations since as a project grows, if an auto-wired property fails it can be difficult to track down exactly why. Additionally explicitly showing where dependencies come from can help with organizing your application and visualizing your application hierarchy.
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'm learning Spring and looking at using Spring Test for my web app (JQuery/CXF/Hibernate). I have been using annotations to wire up my beans and noticed that this sometimes got into the way of polymorphism. For example I have a GenericDAO extended by all DAOs. It is also a concrete class used by simple services, so when I wired it for one of those services, ALL other DAOs became candidates for runtime wiring (because of polymorphism). I could solve that by wiring explicitly by type: #Resource(type= GenericDaoImpl.class), but this goes against the best practice of coding to interfaces ..
Now I want to create unit tests using a MockGenericDaoImpl, and integration tests using GenericDaoImpl. How will I override the annotations? I'm guessing the best approach is to stick to XML-based wiring, so that I can have several versions of beans.xml, one for prod, one for unit tests, one for integration tests, and possibly split them into parallel sub-files, as needed. Isn't this approach more flexible than depending on annotations that either scan to guess the appropriate candidate, or constrain polymorphism?
Can someone give me broad directions on how to organize my test configuration setup? Thank you!
How about using #Configuration class? If you're not familiar with this method - you can declare a class that replaces the XML context file and looks something like this:
#Configuration
#ComponentScan({ "com.project.dao"})
public class TestConfiguration {
#Bean
public GenericDao getGenericDao() {
return new MockGenericDaoImpl();
}
}
In the #ComponentScan annotation just put the relevant packages to scan. This way you're very flexible with the beans you're creating and the way to create them. You can injects mock to the beans whatever way you'd like.
Also you can create several test configurations, each configuration for a different purpose. In order to load the context you need to put this annotation on your test class:
#ContextConfiguration(classes={TestConfiguration .class})
Using XML configuration files prevent you from depending on Spring dependencies. You can replace it with another DI framework(maybe Guice, but this is not realistic for big projects I know). Using XML configuration files enables you to code cleanly.
I hate XML but I hate existence of not-business-logic-specific things in my code more.
I see you know how to overcome the test issues using XML configuration files. I will try to show how to overcome duplication of implementations(one real one mock implementation) problems using annotations.
You can define your beans via annotations. You can select implementation using aliases:
project.dev.properties:
my.project.dao.xDao=xDaoJpaBean
project.test.properties:
my.project.dao.xDao=xDaoMockBean
<alias name="${my.project.dao.xDao}" alias="xDao"/>
#Autowired
#Qualifier("xDao")
protected XDao xDao;
So you can select your implementation just using your properties file. If you want to use Annotations purely you can do this as well:
#Autowired
#Qualifier("${my.project.dao.xDao}")
protected XDao xDao;
Your build environment will specify which properties file to load, in return your bean will be assigned.