Specifying a Maven profile when running JUnit tests within a Spring webapp - java

Background
/pom.xml
...
<properties>
...
<jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
<jdbc.url>jdbc:mysql://${database.host}/${database.name}</jdbc.url>
<jdbc.user>${database.user}</jdbc.user>
<jdbc.password>${database.password}</jdbc.password>
...
</properties>
...
<profiles>
<profile>
<id>dev</id>
<properties>
...
<database.name>database</database.name>
<database.host>localhost</database.host>
<database.user>root</database.user>
<database.password></database.password>
...
</properties>
</profile>
</profiles>
...
/src/main/resources/database.properties
...
jdbc.driver=${jdbc.driver}
jdbc.url=${jdbc.url}
jdbc.user=${jdbc.user}
jdbc.password=${jdbc.password}
...
/src/main/resources/spring/applicationContext.xml
<beans ... xmlns:p="http://www.springframework.org/schema/p" ...>
...
<bean
id="dataSource"
...
p:driverClassName="${jdbc.driver}"
p:url="${jdbc.url}"
p:username="${jdbc.user}"
p:password="${jdbc.password}"
... />
...
</beans>
/src/test/java/com/company/project/service/MyItemServiceImplTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/spring/applicationContext.xml" })
public class MyItemServiceImplTest {
#Resource
private MyItemService myItemService;
#Test
public void testSave() {
MyItem myItem = new MyItem();
myItemService.save(myItem);
...
}
}
Question
When running the tests, it throws an exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'dataSource' defined in class path resource [spring/applicationContext.xml]: Could not resolve placeholder 'database.password'
...
I guess it's because I need to run the tests while specifying the dev profile like I do when I launch the webapp (using -P dev). But I can't make it work. Is it even possible?
PS
The filtered applicationContext.xml file (i.e. the one in /target/classes/spring/applicationContext.xml) is identical to the one in /src/*, but the filtered database.properties file (i.e. /target/classes/database.properties) looks like
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://${database.host}/${database.name}
jdbc.user=${database.user}
jdbc.password=${database.password}
It means that from the pom.xml file to the .properties one, the properties have been well filtered, but within the pom.xml itself, the properties that depend on the chosen profile won't get filtered. Probably because I want to specify anywhere the profile I need when launching the tests. But as I said before, -P dev doesn't seem work with JUnit...

Resource filtering is performed in the process-resources phase. So if you state mvn test -Pdev you will have passed that phase and all filtering has been done. It doesn't matter to JUnit what profile you are running since you are not doing anything else differently in that dev profile.

Related

How to create local database using JPA?

I am just starting to use JPA. I am trying to create database based on schema using Persistence.generateSchema("DataLayer", null) method, but i get an exception. As JPA implementation i am using OpenJPA.
My solution is divided into two Eclipse projects. Both use Maven and module-info.java.
1st project is clearly just main method where i call the method above.
2nd one is JPA entities and data access objects.
In 1st project i included dependency to 2nd project. In 2nd project i included dependencies to jpa implementor (openjpa) and database driver (derby). See dependencies part from pom.xml's bellow:
1st project dependency (there is just my 2nd project):
<dependency>
<groupId>registry</groupId>
<artifactId>datalayer</artifactId>
<version>0.0.1</version>
</dependency>
1st project module-info:
module justtestingTEMP
{
exports justtestingTEMP;
requires registry.datalayer;
requires javax.persistence;
}
2nd project dependencies:
<dependencies>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>10.15.2.0</version>
</dependency>
</dependencies>
2nd project module-info:
module registry.datalayer
{
exports datalayer.other;
exports datalayer.dto;
exports datalayer.dao;
requires javax.persistence;
}
This is persistence.xml (it is in 2nd project):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="DataLayer"
transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>myNonJtaDataSource</non-jta-data-source>
<properties>
<property
name="javax.persistence.schema-generation.database.action"
value="create" />
</properties>
</persistence-unit>
This is the exception:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/sql/DataSource
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newInstance(JDBCBrokerFacto
ry.java:72)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Metho
d)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodA
ccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Delegatin
gMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.openjpa.kernel.Bootstrap.invokeFactory(Bootstrap.java:131)
at org.apache.openjpa.kernel.Bootstrap.newBrokerFactory(Bootstrap.java:66)
at org.apache.openjpa.persistence.PersistenceProviderImpl.getBrokerFactory(Pers
istenceProviderImpl.java:152)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFa
ctory(PersistenceProviderImpl.java:95)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFa
ctory(PersistenceProviderImpl.java:159)
at org.apache.openjpa.persistence.PersistenceProviderImpl.generateSchema(Persis
tenceProviderImpl.java:244)
at javax.persistence#1.1/javax.persistence.Persistence.generateSchema(Persisten
ce.java:188)
at justtestingTEMP/justtestingTEMP.Main.main(Main.java:15)
Caused by: java.lang.ClassNotFoundException: javax.sql.DataSource
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoade
r.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoa
ders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 13 more
Where can i get that javax.sql.DataSource class from? I guess i am missing some dependency or i have configured something wrong.
What i tried: Switch JPA implementation (other exceptions were raised - but about missing classes), add requires java.sql; to module-info.
After adding requires java.sql; to module-info:
Exception in thread "main" java.lang.NoClassDefFoundError: java/lang /instrument/
ClassFileTransformer
at org.apache.openjpa.persistence.PersistenceProviderImpl.loadAgent(Persistence
ProviderImpl.java:365)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFa
ctory(PersistenceProviderImpl.java:102)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFa
ctory(PersistenceProviderImpl.java:159)
at org.apache.openjpa.persistence.PersistenceProviderImpl.generateSchema(Persis
tenceProviderImpl.java:244)
at javax.persistence#1.1/javax.persistence.Persistence.generateSchema(Persisten
ce.java:188)
at justtestingTEMP/justtestingTEMP.Main.main(Main.java:14)
Caused by: java.lang.ClassNotFoundException: java.lang.instrument.ClassFileTrans
former
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoade
r.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoa
ders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 6 more
Found out that required classes were in java.sql and and java.instrument module, so adding these to module-info solve my issue. module-info.java should look like this:
module justtestingTEMP
{
exports justtestingTEMP;
requires java.instrument;
requires java.sql;
requires javax.persistence;
requires registry.datalayer;
}
Also it is possible to remove module-info.java from 1st project. That resulted in a "correct" error saying that i have not defined jdbc driver and connection properties - that is good. No class not found errors. I can create and connect to database now. That is probably because all required modules are available implicitly. With module-info.java i have to define all required modules.

WELD SE with JUnit 5 require enabling bean discovery programmatically

I'm setting up an example project for testing purposes which uses Weld SE and JUnit5 and for some reason, in my test classes, after initializing weld I observ that, for some reason, it's bean discovery is disabled, which in the end, it lead me to this error:
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type Person with qualifiers #Default;
This is my test class :
#EnableWeld
public class SimpleTestA {
#Inject
Person p;
#Test
public void testThatItWorks() {
System.out.println("Hey");
}
}
located in :
projectName\core\model\src\test\java\com\aCompany\projectName\core\model\testmodel\SimpleTestA.java
This is my beans.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all" />
located in :
projectName\core\model\src\main\resources\META-INF\beans.xml
The project structure is fairly simple, I just have a main module named "projectName" which is the parent of the sub-module named "core" which contains all that i pasted earlier. My dependencies list is this :
<dependencies>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit-jupiter.aggregator.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>${weld.se.core.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.weld/weld-junit5 -->
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-junit5</artifactId>
<version>${weld.junit5.version}</version>
<scope>test</scope>
</dependency>
and those are my properties :
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<weld.se.core.version>3.0.1.Final</weld.se.core.version>
<weld.junit5.version>1.3.1.Final</weld.junit5.version>
<junit-jupiter.aggregator.version>5.4.0</junit-jupiter.aggregator.version>
If I modify the test adding the weld initialization attribute with explicit bean discovery activation, everything works very well:
#WeldSetup
WeldInitiator weldInitiator = WeldInitiator.of(WeldInitiator.createWeld().enableDiscovery());
What I'm missing ? If the beans.xml is present, shouldn't the bean discovery activated automatically? Thank you in advance.
So the thing here is that you are using Weld SE (well, weld-junit is), not Weld EE which you might know from servers such as WildFly.
In SE, the discovery is by default off and so called synthetic archive is used.
Synthetic archive only contains whatever you yourself feed it - classes as beans, packages to scan through etc. It doesn't scan whole classpath.
So to make your example work, you can either have the discovery on, or you can add the classes and packages you need via Weld.addPackages(), Weld.addClasses() and so on.
In context of Weld-junit this translates into WeldInitiator.createWeld().addPackages().
The reason why Weld SE (and weld-junit) doesn't perform the whole discovery is because you would effectively scan whole classpath including JDK packages and all. That takes time and on top of that you also discover tons of beans you don't need. Or you can pick up interceptors/alternatives that you didn't mean to. Last but not least, these are meant to be unit tests, so minimal deployments that test your beans.

Deploy a Java EE project as jar with Maven and perform the DI

I've just developed a sample Java EE 7 application.
The code is as follows:
#Stateless
#LocalBean
public class Foo {
#Inject
private Boo boo; // Internal resource
#Asynchronous
public void doFoo(Collection<Object> c) {
boo.doSomething(c);
}
}
With the aim to deploy the project as jar file, I'm using the following Maven configuration:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sample</groupId>
<artifactId>ejb-foo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>ejb-foo</finalName>
</build>
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
</project>
Unfortunately, Maven returns me this warning:
Classpath entry org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER will not be exported or published. Runtime ClassNotFoundExceptions may result. ejb-foo P/ejb-foo Classpath Dependency Validator Message
How can I fix this error?
Note:
The idea is to import that jar into another Java project and then to instance the Foo class as EJB:
import myjavaeeproject.Foo;
public OtherClass {
#EJB
private Foo foo;
public void doMagic(List<String> list) {
foo.doFoo(list);
}
}
Update:
I've fixed the error as shown here.
When I deploy (as war) the target project (that implements OtherClass, annotated as WebServlet) on JBoss, I've an error:
POST_MODULE: JBAS018733: Failed to process phase POST_MODULE of deployment
It depends on the EJB injection.
What am I doing wrong?
As per my examples in comment, it is because eclise think "the library exists at the server and it is not right to export this with your projects"
I don't have much idea about your code, but seems to be ok.
If this is a J2EE application, I would expect the target to be a war or ear. I don't think that a J2EE container will understand a jar deployment.

Spring 3.1 bean visibility using bean definition profiles

I have been experimenting with using Spring 3.1's bean definition profiles and nested beans. I had hoped that I could define different beans depending on the active profile. Consider the following heavily over simplified example such that my Spring context contains something like
<bean id="say" class="test.Say" p:hello-ref="hello"/>
<beans profile="prod">
<bean id="hello" class="test.Hello" p:subject="Production!"/>
</beans>
<beans profile="dev">
<bean id="hello" class="test.Hello" p:subject="Development!"/>
</beans>
I get the following error:
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'say' defined in class path resource
[applicationContext.xml]: Cannot resolve reference to bean 'hello'
while setting bean property 'hello'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'hello' is defined at
org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
at
org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)
aJava Result: 1
I was expecting that the hello bean would be defined according to the active Maven profile (in my case prod or dev). I'm starting to think that the Spring active profiles (spring.profiles.active) may be completely unrelated to Maven profiles.
Could somebody please explain where I am going wrong? (Is this even possible using profiles?).
I was expecting that the hello bean would be defined according to the active Maven profile (in my case prod or dev). I'm starting to think that the Spring active profiles (spring.profiles.active) may be completely unrelated to Maven profiles.
That's true, they are unrelated.
Here is how you can fix it:
Make sure that the web.xml that you have in src/main/webapp/WEB-INF/ folder has the following context setting:
<context-param>
<param-name>spring.profile.active</param-name>
<param-value>${profileName}</param-value>
</context-param>
And then make sure that the maven-war-plugin has filtering turned on for the web.xml:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>
And then lastly in your profiles:
<profiles>
<profile>
<id>dev</id>
<properties>
<profileName>dev</profileName>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<profileName>prod</profileName>
</properties>
</profile>
</profiles>
You could also add a default value in the normal properties section:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<profileName>dev</profileName>
</properties>
So if you run without the -P option the dev spring profile will be used.
When running mvn package the web.xml will have the correct value for the spring.profile.active.
Thanks to maba (whose answer I shall accept), I started thinking about this in a different way.
I've modified the parent bean "say" because it needs to be lazily initialized because when it is initially encountered the nested bean contexts do not yet exist. So the new version adds a new bean and changes the "say" definition such that it now looks like:
<bean class="test.InitProfile" p:profiles="dev"/>
<bean id="say" class="test.Say" lazy-init="true" p:hello-ref="hello"/>
The new InitProfile bean is an InitializingBean responsible for setting up the active profiles.
It contains:
package test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
public class InitProfile implements InitializingBean, ApplicationContextAware {
private ConfigurableApplicationContext ctx;
private String[] profiles;
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = (ConfigurableApplicationContext) ac;
}
public void setProfiles(String inprofiles) {
if (inprofiles.contains(",")) {
profiles = StringUtils.split(inprofiles, ",");
} else {
profiles = new String[]{inprofiles};
}
}
public void afterPropertiesSet() throws Exception {
String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
if (profiles != null && activeProfiles.length == 0) {
ctx.getEnvironment().setActiveProfiles(profiles);
ctx.refresh();
}
}
}
Using this approach has the added advantage of being able to set the active spring profile using a classpath properties file (this can differ depending on my active Maven profile). I also like this approach because I can use it for both web application and command line applications.

JUnit tests pass in Eclipse but fail in Maven Surefire

I have written some JUnit tests using JUnit 4 and spring-test libraries. When I run the tests inside Eclipse then run fine and pass. But when I run them using Maven (during the build process), they fail giving a spring related error. I am not sure what is causing the problem, JUnit, Surefire or Spring. Here is my test code, spring configuration and the exception that I get from Maven:
PersonServiceTest.java
package com.xyz.person.test;
import static com.xyz.person.util.FjUtil.toFjList;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import com.xyz.person.bo.Person;
import com.xyz.person.bs.PersonService;
import fj.Effect;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:personservice-test.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class PersonServiceTest {
#Autowired
private PersonService service;
#Test
#Transactional
public void testCreatePerson() {
Person person = new Person();
person.setName("abhinav");
service.createPerson(person);
assertNotNull(person.getId());
}
#Test
#Transactional
public void testFindPersons() {
Person person = new Person();
person.setName("abhinav");
service.createPerson(person);
List<Person> persons = service.findPersons("abhinav");
toFjList(persons).foreach(new Effect<Person>() {
public void e(final Person p) {
assertEquals("abhinav", p.getName());
}});
}
}
personservice-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<import resource="classpath:/personservice.xml" />
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="true">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:InMemoryDatabase;create=true" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="persistenceUnitName" value="PersonService" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.DerbyDialect" />
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.validator.autoregister_listeners" value="false" />
<entry key="javax.persistence.transactionType" value="RESOURCE_LOCAL" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="datasource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="false" />
<bean id="beanMapper" class="org.dozer.DozerBeanMapper">
<property name="mappingFiles">
<list>
<value>personservice-mappings.xml</value>
</list>
</property>
</bean>
</beans>
Exception in Maven
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.xyz.person.test.PersonServiceTest
23:18:51,250 WARN JDBCExceptionReporter:77 - SQL Warning: 10000, SQLState: 01J01
23:18:51,281 WARN JDBCExceptionReporter:78 - Database 'InMemoryDatabase' not created, connection made to existing database instead.
23:18:52,937 WARN JDBCExceptionReporter:77 - SQL Warning: 10000, SQLState: 01J01
23:18:52,937 WARN JDBCExceptionReporter:78 - Database 'InMemoryDatabase' not created, connection made to existing database instead.
23:18:52,953 WARN TestContextManager:429 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener#359a359a] to process 'after' execution for test: method [public void com.xyz.person.test.PersonServiceTest.testCreatePerson()], instance [com.xyz.person.test.PersonServiceTest#1bc81bc8], exception [org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! JpaTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single JpaTransactionManager for all transactions on a single DataSource, no matter whether JPA or JDBC access.]
java.lang.IllegalStateException: No value for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#3f563f56] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:199)
at org.springframework.orm.jpa.JpaTransactionManager.doCleanupAfterCompletion(JpaTransactionManager.java:489)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1011)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:804)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:515)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:290)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:183)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:426)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:90)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:115)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:102)
at org.apache.maven.surefire.Surefire.run(Surefire.java:180)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:599)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
23:18:53,078 WARN TestContextManager:377 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener#359a359a] to process 'before' execution of test method [public void com.xyz.person.test.PersonServiceTest.testFindPersons()] for test instance [com.xyz.person.test.PersonServiceTest#79f279f2]
org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! JpaTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single JpaTransactionManager for all transactions on a single DataSource, no matter whether JPA or JDBC access.
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:304)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.startTransaction(TransactionalTestExecutionListener.java:507)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:269)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:162)
at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:374)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:115)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:102)
at org.apache.maven.surefire.Surefire.run(Surefire.java:180)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:599)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
Tests run: 3, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 15.625 sec <<< FAILURE!
Results :
Tests in error:
testCreatePerson(com.xyz.person.test.PersonServiceTest)
testCreatePerson(com.xyz.person.test.PersonServiceTest)
testFindPersons(com.xyz.person.test.PersonServiceTest)
Tests run: 3, Failures: 0, Errors: 3, Skipped: 0
I had the same problem (JUnit tests failed in Maven Surefire but passed in Eclipse) and managed to solve it by setting forkMode to always in the maven surefire configuration in pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<forkMode>always</forkMode>
</configuration>
</plugin>
Surefire parameters: http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html
Edit (January 2014):
As Peter Perháč pointed out, the forkMode parameter is deprecated since Surefire 2.14. Beginning from Surefire 2.14 use this instead:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<reuseForks>false</reuseForks>
<forkCount>1</forkCount>
</configuration>
</plugin>
For more information see Fork Options and Parallel Test Execution
I suddenly experienced this error, and the solution for me was to disable to run tests in parallel.
Your milage may vary, since I could lower number of failing tests by configuring surefire to run parallel tests by ´classes´.:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<parallel>classes</parallel>
<threadCount>10</threadCount>
</configuration>
</plugin>
As I wrote first, this was not enough for my test suite, so I completely disabled parallel by removing the <configuration> section.
Test execution result different from JUnit run and from maven install seems to be symptom for several problems.
Disabling thread reusing test execution did also get rid of the symptom in our case, but the impression that the code was not thread-safe was still strong.
In our case the difference was due to the presence of a bean that modified the test behaviour. Running just the JUnit test would result fine, but running the project install target would result in a failed test case. Since it was the test case under development, it was immediately suspicious.
It resulted that another test case was instantiating a bean through Spring that would survive until the execution of the new test case. The bean presence was modifying the behaviour of some classes and producing the failed result.
The solution in our case was getting rid of the bean, which was not needed in the first place (yet another prize from the copy+paste gun).
I suggest everybody with this symptom to investigate what the root cause is. Disabling thread reuse in test execution might only hide it.
I had a similar problem, the annotation #Autowired in the test code did not work under using the Maven command line while it worked fine in Eclipse. I just update my JUnit version from 4.4 to 4.9 and the problem was solved.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
This doesn't exactly apply to your situation, but I had the same thing -- tests that would pass in Eclipse failed when the test goal from Maven was run.
It turned out to be a test earlier in my suite, in a different package. This took me a week to solve!
An earlier test was testing some Logback classes, and created a Logback context from a config file.
The later test was testing a subclass of Spring's SimpleRestTemplate, and somehow, the earlier Logback context was held, with DEBUG on. This caused extra calls to be made in RestTemplate to log HttpStatus, etc.
It's another thing to check if one ever gets into this situation. I fixed my problem by injecting some Mocks into my Logback test class, so that no real Logback contexts were created.
I have the similar problem, but with IntelliJ IDEA + Maven + TestNG + spring-test. (spring-test is essential of course :) )
It was fixed when I've change config of maven-surefire-plugin to disable run tests in parallel. Like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<skipTests>${maven.test.skip}</skipTests>
<trimStackTrace>false</trimStackTrace>
<!--<parallel>methods</parallel>-->
<!-- to skip integration tests -->
<excludes>
<exclude>**/IT*Test.java</exclude>
<exclude>**/integration/*Test.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skipTests>${maven.integration-test.skip}</skipTests>
<!-- Make sure to include this part, since otherwise it is excluding Integration tests -->
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/IT*Test.java</include>
<include>**/integration/*Test.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
I had the same issue, but the problem for me was that Java assertions (e.g. assert(num > 0)) were not enabled for Eclipse, but were enabled when running maven.
Therefore running the jUnit tests from Eclipse did not catch trigger the assertion error.
This is made clear when using jUnit 4.11 (as opposed to the older version I was using) because it prints out the assertion error, e.g.
java.lang.AssertionError: null
at com.company.sdk.components.schema.views.impl.InputViewHandler.<init>(InputViewHandler.java:26)
at test.com.company.sdk.util.TestSchemaExtractor$MockInputViewHandler.<init>(TestSchemaExtractor.java:31)
at test.com.company.sdk.util.TestSchemaExtractor.testCreateViewToFieldsMap(TestSchemaExtractor.java:48)
I had a similar problem with a different cause and therefore different solution. In my case, I actually had an error where a singleton object was having a member variable modified in a non-threadsafe way. In this case, following the accepted answers and circumventing the parallel testing would only hide the error that was actually revealed by the test. My solution, of course, is to fix the design so that I don't have this bad behavior in my code.
[I am not sure that this is an answer to the original question, since the stacktrace here looks slightly different, but it may be useful to others.]
You can get tests failing in Surefire when you are also running Cobertura (to get code coverage reports). This is because Cobertura requires proxies (to measure code use) and there is some kind of conflict between those and Spring proxies. This only occurs when Spring uses cglib2, which would be the case if, for example, you have proxy-target-class="true", or if you have an object that is being proxied that does not implement interfaces.
The normal fix to this is to add an interface. So, for example, DAOs should be interfaces, implemented by a DAOImpl class. If you autowire on the interface, everything will work fine (because cglib2 is no longer required; a simpler JDK proxy to the interface can be used instead and Cobertura works fine with this).
However, you cannot use interfaces with annotated controllers (you will get a runtime error when trying to use the controller in a servlet) - I do not have a solution for Cobertura + Spring tests that autowire controllers.
I had a similar problem: JUnit tests failed in Maven Surefire but passed in Eclipse when I used JUnit library version 4.11.0 from SpringSource Bundle Repository. Particulary:
<dependency>
<groupId>org.junit</groupId>
<artifactId>com.springsource.org.junit</artifactId>
<version>4.11.0</version>
</dependency>
Then I replaced it with following JUnit library version 4.11 and everything works fine.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
I had this problem today testing a method that converted an object that contained a Map to a JSON string. I assume Eclipse and the Maven surefire plugin were using different JREs which had different implementations of HashMap ordering or something, which caused the tests run through Eclipse to pass and the tests run through surefire to fail (assertEquals failed). The easiest solution was to use an implementation of Map that had reliable ordering.
This has helped me in troubleshooting my problem. I had a similar symptoms in that maven would fail however running junit tests runs fine.
As it turns out my parent pom.xml contains the following definition:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<forkMode>pertest</forkMode>
<argLine>-Xverify:none</argLine>
</configuration>
</plugin>
And in my project I override it to remove the argLine:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>pertest</forkMode>
<argLine combine.self="override"></argLine>
</configuration>
</plugin>
Hopefully this will help someone in troubleshooting surefire plugin.
In my case the reason was a bug in the code. The test relied on a certain order of elements in a HashSet, which turned out to be different when run either in Eclipse or in Maven Surefire.
I had a similar problem, I ran my tests disabling the reuse of forks like this
mvn clean test -DreuseForks=false
and the problem disappeared.
The downside is that the overall test execution time will be longer, that's why you may want to do this from the command line only if necessary
You don't need to inject a DataSource in the JpaTransactionManager since the EntityManagerFactory already has a datasource. Try the following:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Usually when tests pass in eclipse and fail with maven it is a classpath issue because it is the main difference between the two.
So you can check the classpath with maven -X test and check the classpath of eclipse via the menus or in the .classpath file in the root of your project.
Are you sure for example that personservice-test.xml is in the classpath ?
I had the same problem, and the solution for me was to allow Maven to handle all dependencies, including to local jars. I used Maven for online dependencies, and configured build path manually for local dependencies.
Thus, Maven was not aware of the dependencies I configured manually.
I used this solution to install the local jar dependencies into Maven:
How to add local jar files in maven project?
It is most likely that your configuration files are in src/main/resources, while they must be under src/test/resources to work properly under maven.
https://cwiki.apache.org/UIMA/differences-between-running-unit-tests-in-eclipse-and-in-maven.html
I'm replying this after two years 'cause I couldn't find this answer here and I think it is the right one.

Categories