Now that Alfresco integration tests of custom modules are run using Docker, I wonder how to make additional Spring beans available in this context and how to access existing Spring beans in test classes.
Until Alfresco 5.x, I used to annotate the test class with
#ContextConfiguration("classpath:alfresco/application-context.xml")
This made the Spring context available. To make Spring beans from this context available in the test class, I annotated members like this:
#Autowired
#Qualifier("authenticationComponent")
private AuthenticationComponent authenticationComponent;
In addition I was able to define additional Spring beans in src/test/resources/alfresco/extension/test-context.xml.
Is this the approach to use when writing integration tests for 6.x and Docker?
At least the annotation org.springframework.test.context.ContextConfiguration is no longer included in a module build using the Maven 4.0.0 SDK archetype.
This blog post talks about the above mentioned annotations. But the dependencies pulled in by the pom.xml created from the SDK 4 archetype don't include these annotations.
A different approach seems to be to only use
#RunWith(value = AlfrescoTestRunner.class)
on the integration test class. But how do I get the Spring beans like nodeService injected into it? And how do I declare and make available additional Spring beans which are part of my custom module and required by the integration test to succeed?
You can get the Spring context via AlfrescoTestRunner as follows:
#Before
public void setUp() {
this.nodeService = (NodeService) super.getApplicationContext().getBean("nodeService");
}
I do the same with custom beans:
super.getApplicationContext().getBean(MyType.class);
Since the integration tests run in the repository, all of the Spring context is automatically available.
Note that your test class needs to extend AbstractAlfrescoIT for this to work.
An example class may look like this:
package nl.open.mystuff;
import org.alfresco.rad.test.AbstractAlfrescoIT;
import org.alfresco.rad.test.AlfrescoTestRunner;
import org.alfresco.service.cmr.repository.NodeService;
#RunWith(value = AlfrescoTestRunner.class)
public class MyCustomIT extends AbstractAlfrescoIT {
private NodeService nodeService;
private MyType myType;
#Before
public void setUp() {
this.nodeService = (NodeService) super.getApplicationContext().getBean("NodeService");
this.myType = super.getApplicationContext().getBean(MyType.class);
}
}
In Alfresco SDK 3, you can even add your own Spring XML files under src/test/resources/alfresco/extension/*-context.xml. I imagine this still works, but I haven't tried it with SDK 4 myself.
Related
I'm trying to write an integration test for a spring boot project. Unfortunately, I'm confused with the implementation.
Below sample code snippet tried
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MainApplication.class)
#AutoConfigureMockMvc
public class PropertyControllerIT {
#Autowired
private MockMvc mockMvc;
#Test
public void sample_test() throws Exception {
this.mockMvc.perform(post("/property")).andExpect(status().is2xxSuccessful());
}
}
Question
Do I need to have a separate MainClass with
#SpringBootApplication annotated to support the integration test?
Do we create a mock database or override the database configuration. If yes, how do we override the configuration
Should we maintain a separate directory for integration-test similar to java or test like integration-test
You don't need to create any other classes annotated with
SpringBootApplication.
It's a good practice to run integration tests using in memory database for example H2. You can create a new application-test.properties file in resources folder inside of test directory. In order to use override properties you can run test with test profile. In order to run tests with test profile #ActiveProfiles can be used.
You can keep your integration tests in the same test directory like unit test but they can be located in a separate package
I develop web app with Spring Boot. I have problem with unit test for web layer.
For these tests I'm using annotation #WebMvcTest. Problem is that my main configuration class contains #PropertySource with java arg, which contains path to external properties file, and when I start my unit web test, error is occured that this java arg can't be parsed(of course I can add this java arg to run configuration of my test, but my web unit tests don't need this file).
My main config class:
#SpringBootApplication
#PropertySource(value = {"${pathto.configfile}"})
#EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
My first solution was to create separate configuration class with "!test" profile, and relocate #PropertySource("..") to it. And to my unit test add #ActiveProfiles("test")
My second Configuration class:
#Configuration
#Profile({"!test"})
#PropertySource(value = {"${pathto.configfile}"})
public class PropertyConfiguration {
}
For unit web test this solution works very good. But new problem appears in starting of my web app. In my external properties file I have
property spring.profiles.active. To this property I assign or db or file value. Depending on its value, apropriate implementation of Repository is created and injected to my service layer. When value is db, app starts good,
but when value is file error is being thrown: NoSuchBeanDefinitionException.
When I come back to my previous version(without second configuration file), app starts good in both cases(but not web unit tests)
So, explain please, why when value of spring.profiles.active=db, app starts good, but when spring.profiles.active=file- failed.And how I can solve my task?
I attempted to find how I can add other application context to my web unit tests, but I didn't find.
Any idea?:)
For my database repositories I'm using Spring Data JPA, so I don't create implementation of these repositories, but I create implementations of my file
repositories, and my implementations had #Profile("file"). After deleting this annotation from implementations, it leaved only on interfaces. I don't know why one config class worked, but two classes didn't. But problem is solved)
I am currently using Spring 4.0.6.RELEASE and have the following Spring configuration file:
#Configuration
#PropertySource({"classpath:config.properties"})
public class MyServiceConfig {
...
I was wondering if there is a way to run integration tests for my component-annotated-classes with a different properties file (let's say test-config.properties) in order to give different values for my value and autowired annotated properties and methods.
NOTE: I know that Spring 4.1.x comes with #TestPropertySource which helps to achieve it. But upgrading Spring to later versions is not an option.
Yes. Specify "profile" for integration tests.
#Configuration
#PropertySource({"classpath:test-config.properties"})
#Profile("integration-test")
public class MyServiceTestConfig {
...
In order to use this profile when testing repository use #ActiveProfiles annotation
#ActiveProfiles("integration-test")
#RunWith(SpringJUnit4ClassRunner.class)
public class MyRepositoryTest {
...
I am integrating Java Plugin Framework within a Spring based web application (XML-free).
Everything is fine, except for the dependency injection in plugin context
For instance I have a data source I would like to use in a plugin without having to go back to property files by using #Autowired like for the rest of the application
I cannot find a way to do this except by using getBean, which I read was not the best practise on this subject.
I also had a look at LogicalDoc but this project resorts to properties reloading which is not the correct solution for me as I want beans attributes modifications to be available without further glue.
Does anyone know of an existing open source project where both these environment are used ?
Not being able to inject dependencies in plugins, I finally added the following methods to mother class of all plugins
public void setContext(ApplicationContextProvider a_ctx) {
m_theContext = a_ctx;
}
public ApplicationContext getApplicationContext() {
return m_theContext.getApplicationContext();
}
And retreive the beans from within the plugin by
getApplicationContext().getBean(*ClassType*)
I am trying to enable Spring autowiring support in my webservice, following the lines of
public class MyService extends SpringBeanAutowiringSupport implements SomeInterface {
private Dao dao;
#Autowired
public void setDao(Dao dao) {
this.dao = dao;
}
With the MyService class annotated with
#WebService(endpointInterface = "SomeInterfacePath")
However, when I try and run this, I get a
java.lang.NoSuchMethodError: org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext()Lorg/springframework/web/context/WebApplicationContext;
at org.springframework.web.context.support.SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(SpringBeanAutowiringSupport.java:81)
at org.springframework.web.context.support.SpringBeanAutowiringSupport.<init>(SpringBeanAutowiringSupport.java:68)
error, which I haven't been able to find a resolution to. I'm using Spring 3.0 jars and apache-cxf. Spring autowiring works elsewhere in my project but doesn't seem to play nicely here. Any ideas as to what is going on? I have a a jaxws endpoint defined in my appConfig as
<jaxws:endpoint
id="myendpoint"
implementor="MyService"
address="/helloworld
/>
Until recently, Apache CXF pulled Spring 2.5.5 as a maven dependency.
However, CXF Version 2.3 and newer use Spring 3.
Apache CXF parent pom 2.2.1:
<spring.version>2.5.5</spring.version>
Apache CXF parent pom 2.3:
<spring.version>3.0.4.RELEASE</spring.version>
Both include a <dependencymanagement> section that ties Spring to the specified version.