How would you go about integration testing a spring application that is annotation-configured and component-scanned and does not have an XML configuration at all? I'm hitting a wall with the need to replace production components with testing components without actually resorting to xml configuration or reflection injections to all the #autowired parts.
Example:
interface A {...}
#Component
class AImpl implements A {
...
}
interface B {...}
#Component
class BImpl implements B {
#Autowired A a;
...
}
interface C {...}
class CImpl implements C {
#Autowired B b;
...
}
then in my test I want to use ATestImpl, but I only have access to C (integration testing C).
How would you go about doing that?
Take advantage of #Primary annotation:
#Service
#Primary
public class TestA implements A {
//...
}
If there is more than one bean implementing A, Spring will prefer the one annotated with #Primary. If you place TestA class in /src/test/java, it will only be picked up during test execution, on normal context startup Spring won't see TestA and use only avaialble AImpl.
Use a dedicated spring context XML file where you override AImpl with an instance of ATestImpl. Of course, it uses XML, but I don't see any other solution (other than repackaging the application with your ATestImpl annotated class instead of the AImpl one)
The new Bean Profile features in Spring 3.1 address the need to swap injected components for testing by defining profiles e.g. test, production etc.
The link to the blog post is here. The Spring team have today released the second milestone release of Spring 3.1.
You can use a special component scan for your test, that exclude the "normal" class and add the test class.
If you have several different test classes, then they should not have a #Component Annotation (or #Service, ...). Instead they should be loaded by an XML Bean declaration. So you can have different XML files for different setups.
<context:component-scan base-package="com.queomedia.sgcrm.base">
<context:exclude-filter expression="com\.example\.AImpl" type="regex"/>
</context:component-scan>
<bean class="com.example.ATestImpl"/>
Using Spring annotation config classes, code the #Bean methods to interfaces. The prod config can perform a componentscan on the high-level package(s) to load the prod objects and the test configs can individually specify beans to return the test versions of your objects. This works very well for component testing where faking service calls and DAO objects is necessary.
Related
Hello I am finding the solution for getting the bean instantiated given in #ContextConfiguration when we run the Vaadin test case with spring boot.
Here is some piece of the code which I have configured.
#WebAppConfiguration
#RunWith(JUnit4.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = UIConfiguration.class)
public abstract class BaseTestCase extends TestBenchTestCase {
//code stuff
}
#Configuration
#PropertySource("classpath:META-INF/spring/application.properties")
#ComponentScan(basePackages = "com.ui", excludeFilters = #ComponentScan.Filter(value = Controller.class, type = FilterType.ANNOTATION))
#EnableAsync
#EnableI18N
public class UIConfiguration implements AsyncConfigurer {
//block of code
}
You should be able to use the ClassRule and Rule Spring provide if you do not want to use the SpringRunner
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
See the java doc for more details,
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit4/rules/SpringClassRule.html
SpringClassRule is a custom JUnit TestRule that supports class-level features of the Spring TestContext Framework in standard JUnit tests by means of the TestContextManager and associated support classes and annotations.
In contrast to the SpringJUnit4ClassRunner, Spring's rule-based JUnit support has the advantage that it is independent of any Runner and can therefore be combined with existing alternative runners like JUnit's Parameterized or third-party runners such as the MockitoJUnitRunner.
In order to achieve the same functionality as the SpringJUnit4ClassRunner, however, a SpringClassRule must be combined with a SpringMethodRule, since SpringClassRule only supports the class-level features of the SpringJUnit4ClassRunner.
I'm attempting to set up some Spring Boot JPA tests using:
package biz.ianw.coindatabase.test;
#RunWith(SpringRunner.class)
#DataJpaTest
public class DbTests {
#Test
public void test1() { ... }
}
I have a service class:
package biz.ianw.coindatabase.database;
//#Service
#Repository
#Transactional(readOnly=false)
public class CoinDbService { ... }
and an application:
package biz.ianw.coindatabase;
#SpringBootApplication
#Slf4j
#Configuration
#EnableEncryptableProperties
public class Main {
#Autowired
CoinDbService dbService;
... }
Starting the test gives the error:
Field dbService in biz.ianw.coindatabase.Main required a bean of type 'biz.ianw.coindatabase.database.CoinDbService' that could not be found.
This is, I assumed, something to do with the type of beans #DataJpaTest loads during startup:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.
I'm not quite sure why #Service classes should be considered as not required for JPA testing, but I tried to force the matter by annotating it as #Repository instead, but to no avail.
I can manually load the class with #Import(...) but it seems a tad hooky. Is there a better way to tell DataJpaTest what I need for testing?
I am quoting from DataJpaTest documentation where you can find the answer to your question.
Annotation that can be used in combination with
#RunWith(SpringRunner.class) for a typical JPA test. Can be used when
a test focuses only on JPA components.
Using this annotation will disable full auto-configuration and instead
apply only configuration relevant to JPA tests.
By default, tests annotated with #DataJpaTest will use an embedded
in-memory database (replacing any explicit or usually auto-configured
DataSource). The #AutoConfigureTestDatabase annotation can be used to
override these settings.
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.
What is the difference between mocking service and assign instance of class to service?
For example:
class MyService {
def CallServiceMethod(){
my business logic
}
}
class MyController {
def myService
def callServiceMethod(){
myService.callServiceMethod()
}
}
#TestFor(MyController)
class MyControllerTests {
#Before
void setup() {
controller?.myService = new MyService()
vs
controller?.myService = mockFor(MyService)
}
void testCallServiceMethod(){
controller.callServiceMethod()
}
}
Any one help me please?
When using Spring, you typically lose a lot of behavior if you create a new instance of a class that's registered as a Spring bean. Beans often have multiple other beans dependency-injected into them and those fields would be null in a plain new instance, and various annotations trigger wrapping the bean instance in one or more proxies that add extra checks and behavior before and/or after your methods are called - and that won't happen with a new instance. These proxies include the transactional wrapper you get with #Transactional, the cache checks from #Cacheable, and security checks from #Secured and other Spring Security annotations.
In addition, Grails adds a lot of code to most artifacts (in particular domain classes and controllers). Most of that is added to the bytecode, but some is added at runtime to the metaclass. Although the bytecode is there for a new instance, it often needs a final bit of configuration at runtime. For example there are over 100 GORM methods added to domain classes, but they don't work by themselves and need to be "hooked up" to the current GORM implementation (Hibernate, MongoDB, etc.) This is why you sometimes see an error like "this class was used outside of a Grails application" - the class for some reason didn't have a GORM impl attached, so it can't function.
mockFor and annotations like #TestFor and #Mock don't add all of this behavior, but they do add a large subset of it, and they add mocked but realistic implementations of many methods. The goal is to give the collaborators of your class under test enough run-app-like behavior that they work essentially like they would in a real app, so you can focus on the class being tested without having to think about configuring a test database, or fake web requests and responses, etc.
I am currently fronting issues mixing a CXF web service with Spring #Configurable annotation.
From one side I have my CXF web service fully working and configured like this :
<import resource="classpath:some-other-context.xml" />
<jaxws:server id="Init"
serviceClass="package.to.my.ServiceInterface"
address="/">
<jaxws:serviceBean>
<bean class="package.to.my.BADematInitImpl">
</bean>
</jaxws:serviceBean>
</jaxws:server>
<context:spring-configured />
And in my some-other-context.xml is my Spring configuration containing the following Bean's :
#Configurable(autowire = Autowire.BY_TYPE)
public class MyConfigurable {
#Autowired(required=true)
private A a;
#Autowired(required=true)
private B b;
#Autowired(required=true)
private C c;
...
}
But when I try to create a new instance of MyConfigurable bean into my service, I get a NullPointerException due to the null valued supposed-autowired A,B and C objects.
Any idea ?
#Configurable is a marker used by the AOP load-time-weaving stuff. I assume you are not using any AOP, because there is nothing mentioned about it in your question. Second thing: you don't have to use required=true in your #Autowired annotation as true is the default value of required. I would suggest you to change your code like this:
Add these to elements in your spring configuration file:
<context:component-scan base-package="your.pckg.toscan"/>
Documentation says:
Scans the classpath for annotated components that will be
auto-registered as Spring beans. By default, the Spring-provided
#Component, #Repository, #Service, and #Controller stereotypes will
be detected.
<context:annotation-config/>
Documentation says:
Activates various annotations to be detected in bean classes: Spring's
#Required and #Autowired, as well as JSR 250's #PostConstruct,
#PreDestroy and #Resource (if available), JAX-WS's #WebServiceRef (if
available), EJB3's #EJB (if available), and JPA's #PersistenceContext
and #PersistenceUnit (if available). Alternatively, you may choose to
activate the individual BeanPostProcessors for those annotations.
So changing your code to:
#Component
public class MyConfigurable {
#Autowired
private A a;
#Autowired
private B b;
#Autowired
private C c;
...
}
Everything should work just fine.
I finally found out the problem.
I needed to add this configuration into my third-part application XML files :
<context:load-time-weaver/>
... and add this argument to my jvm launch command line :
-javaagent:"path\to\my\spring-agent.jar"
And it just works like a charm.
I understand that this is because Spring needs at some point to have an entity managing its AOP part so that the dependencies are well injected. It would be interesting if someone had further explanations.
I'm currently learning the new Java EE 6 component models and am confused with the latest dependency injection mechanism. So here are my questions:
1) What is the difference between #Inject and #EJB
2) If I have a simple POJO that contains another POJOs (which one of them is the DAO code), what would be the better choice: #Inject or #EJB?
Can I mix #Inject and #EJB?
An example would be:
ClassA implements InterfaceA and has
an instance of ClassA_Adaptor
ClassA_Adaptor implements InterfaceAB
and has an instance of ClassB
ClassB implements InterfaceB and has
an instance of ClassB_Adaptor and an
instance DAO_ClassB
ClassB_Adaptor implements InterfaceB
and has an instance of ClassC
ClassC implements InterfaceBC and has
an instance of WebService_ClassC
DAO_ClassB will use JPA 2.0
(#PersistenceContext)
I'd like to inject all of them including the DAO and the WebService.
3) Is it a bad approach to only use transactional for certain operations but not for all?
As an example: Some methods in DAO_ClassB are your typical query, while other methods are "write" methods. Is it bad to not wrap the "READ" methods with transaction?
To my understanding, the DAO_ClassB can be wrapped with transaction using #EJB (inject the DAO_ClassB and make all methods transactional). How can I control it?
Sorry if some of the questions are confusing because I know only bits and pieces of the Java EE 6 new component model.
#EJB injects EJBs only, but #Inject can be used to inject POJOs rather than EJBs. However, #Inject requires that your archive be a BDA (contain beans.xml for EE 6, or implicitly in EE 7). #Inject also has additional CDI-specific capabilities (scopes, interceptors, etc.), but those capabilities incur extra overhead. Application servers have support for specifying #EJB bindings so that a deployer can choose the target EJB, but #Inject only allows the application developer to choose the target EJB (and it must exist in the application).
If the target is not an EJB, then you must not use #EJB.
It depends whether you're making multiple inter-related queries and then attempting to make business decisions. You need to understand isolation levels and take them into consideration, even for read-only operations.
From Adam Biens Weblog:
You can use both annotations to inject EJBs. Start with #Inject and if you encounter any problems, switch to #EJB.
#Inject does not have any methods / attributes--it is just a plain annotation:
#Target(value = {ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
#Documented
public #interface Inject {
}
On the other hand, the #EJB annotation allows you to pass additional information, which could be useful to reference remote EJBs, or EJBs which cannot be simple injected in the "Convention over Configuration" style:
#Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface EJB {
public String name() default "";
public String beanName() default "";
public Class beanInterface() default Object.class;
public String mappedName() default "";
}
#Inject is more general than EJB and is part of CDI specification. So if you want to use #Inject, you need an implementation of it in your server.
For POJOs (not EJBs) you have to use #Inject.