Eu escrevi alguns testes JUnit usando JUnit 4 e bibliotecas de teste de primavera. Quando executo os testes dentro do Eclipse, corro bem e passo. Mas quando eu os executo usando o Maven (durante o processo de compilação), eles falham dando um erro relacionado ao spring. Não tenho certeza do que está causando o problema, JUnit, Surefire ou Spring. Aqui está meu código de teste, configuração de primavera e a exceção que recebo do 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());
}});
}
}
peopleervice-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>
Exceção em 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
Respostas:
Tive o mesmo problema (os testes JUnit falharam no Maven Surefire, mas passaram no Eclipse) e consegui resolvê-lo definindo forkMode para sempre na configuração maven infalível em pom.xml:
Parâmetros Surefire: http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html
Editar (janeiro de 2014):
Como Peter Perháč apontou, o parâmetro forkMode está obsoleto desde o Surefire 2.14. A partir do Surefire 2.14, use este:
Para obter mais informações, consulte Opções de bifurcação e execução de teste paralela
fonte
De repente, tive esse erro, e a solução para mim foi desabilitar a execução de testes em paralelo.
Sua milhagem pode variar, já que eu poderia diminuir o número de testes com falha configurando o infalível para executar testes paralelos por ´classes´ .:
Como escrevi primeiro, isso não foi suficiente para minha suíte de testes, então desativei completamente o paralelo removendo a
<configuration>
seção.fonte
Eu tive um problema semelhante, a anotação
@Autowired
no código de teste não funcionou usando a linha de comando do Maven enquanto funcionou bem no Eclipse. Acabei de atualizar minha versão JUnit de 4.4 para 4.9 e o problema foi resolvido.fonte
Isso não se aplica exatamente à sua situação, mas eu tive a mesma coisa - os testes que passariam no Eclipse falharam quando o objetivo do teste do Maven foi executado.
Acabou sendo um teste anterior em minha suíte, em um pacote diferente . Isso me levou uma semana para resolver!
Um teste anterior estava testando algumas classes Logback e criou um contexto Logback a partir de um arquivo de configuração.
O teste posterior estava testando uma subclasse de SimpleRestTemplate do Spring e, de alguma forma, o contexto Logback anterior foi mantido, com DEBUG ativado. Isso fez com que chamadas extras fossem feitas em RestTemplate para registrar HttpStatus, etc.
Outra coisa é verificar se alguém chega a esta situação. Corrigi meu problema injetando alguns Mocks em minha classe de teste Logback, de modo que nenhum contexto real de Logback foi criado.
fonte
Eu tenho o problema semelhante, mas com IntelliJ IDEA + Maven + TestNG + spring-test. ( spring-test é essencial, claro :)) Foi corrigido quando eu mudei a configuração do maven-surefire-plugin para desabilitar os testes de execução em paralelo. Como isso:
fonte
O resultado da execução do teste diferente de
JUnit run
e demaven install
parece ser um sintoma de vários problemas.Desativar a execução de teste de reutilização de thread também eliminou o sintoma em nosso caso, mas a impressão de que o código não era seguro para thread ainda era forte.
No nosso caso, a diferença se deu pela presença de um bean que modificou o comportamento do teste. Executar apenas o teste JUnit resultaria bem, mas executar o
install
destino do projeto resultaria em um caso de teste com falha. Como era o caso de teste em desenvolvimento, foi imediatamente suspeito.Resultou que outro caso de teste instanciava um bean por meio do Spring que sobreviveria até a execução do novo caso de teste. A presença do feijão estava modificando o comportamento de algumas classes e produzindo o resultado com falha.
A solução no nosso caso foi livrar-se do bean, o que não era necessário em primeiro lugar (mais um prêmio da arma de copiar + colar ).
Eu sugiro que todos com este sintoma investiguem qual é a causa raiz. Desativar a reutilização de thread na execução do teste pode apenas ocultá-lo.
fonte
Eu tive o mesmo problema, mas o problema para mim era que as asserções Java (por exemplo, assert (num> 0)) não estavam habilitadas para o Eclipse, mas eram habilitadas ao executar o maven.
Portanto, a execução de testes jUnit no Eclipse não detectou o erro de asserção.
Isso fica claro ao usar o jUnit 4.11 (em oposição à versão anterior que eu estava usando) porque ele imprime o erro de declaração, por exemplo
fonte
Tive um problema semelhante com uma causa diferente e, portanto, uma solução diferente. No meu caso, eu realmente tive um erro onde um objeto singleton estava tendo uma variável de membro modificada de uma maneira não threadsafe. Nesse caso, seguir as respostas aceitas e contornar o teste paralelo apenas ocultaria o erro realmente revelado pelo teste. Minha solução, claro, é consertar o design para que eu não tenha esse mau comportamento no meu código.
fonte
[Não tenho certeza de que esta seja uma resposta à pergunta original, pois o rastreamento de pilha aqui parece um pouco diferente, mas pode ser útil para outros.]
Você pode obter testes com falha no Surefire quando também estiver executando o Cobertura (para obter relatórios de cobertura de código). Isso ocorre porque Cobertura requer proxies (para medir o uso de código) e há algum tipo de conflito entre eles e os proxies Spring. Isso ocorre apenas quando o Spring usa cglib2, o que seria o caso se, por exemplo, você tivesse
proxy-target-class="true"
, ou se você tivesse um objeto que está sendo proxy que não implementa interfaces.A correção normal para isso é adicionar uma interface. Portanto, por exemplo, DAOs devem ser interfaces, implementadas por uma classe DAOImpl. Se você ligar automaticamente na interface, tudo funcionará bem (porque o cglib2 não é mais necessário; um proxy JDK mais simples para a interface pode ser usado em vez disso e o Cobertura funciona bem com isso).
No entanto, você não pode usar interfaces com controladores anotados (você obterá um erro de tempo de execução ao tentar usar o controlador em um servlet) - eu não tenho uma solução para os testes Cobertura + Spring que autowire controladores.
fonte
Tive um problema semelhante: os testes JUnit falharam no Maven Surefire, mas foram aprovados no Eclipse quando usei a biblioteca JUnit versão 4.11.0 do SpringSource Bundle Repository. Particularmente:
Então eu o substituí com a seguinte biblioteca JUnit versão 4.11 e tudo funciona bem.
fonte
Tive esse problema hoje testando um método que converteu um objeto que continha um
Map
em uma string JSON. Presumo que o Eclipse e o plug-in infalível Maven estavam usando JREs diferentes que tinham diferentes implementações deHashMap
ordenação ou algo assim, o que fez com que os testes executados através do Eclipse passassem e os testes executados através do infalível falhassem (assertEquals
falhou). A solução mais fácil foi usar uma implementação de Map com ordenação confiável.fonte
Você não precisa injetar um DataSource no JpaTransactionManager, pois o EntityManagerFactory já tem um datasource. Experimente o seguinte:
fonte
Normalmente, quando os testes passam em eclipse e falham com maven, é um problema de classpath porque é a principal diferença entre os dois.
Portanto, você pode verificar o classpath com maven -X test e verificar o classpath do eclipse por meio dos menus ou no arquivo .classpath na raiz do seu projeto.
Tem certeza, por exemplo, de que personservice-test.xml está no classpath?
fonte
Isso me ajudou a solucionar meu problema. Eu tive um sintoma semelhante em que o maven falhou, no entanto, a execução de testes junit funciona bem.
Acontece que meu pai, pom.xml, contém a seguinte definição:
E no meu projeto eu o substituo para remover o argLine:
Esperançosamente, isso ajudará alguém a solucionar o plug-in infalível.
fonte
<forkMode>
DESCONTINUADO desde a versão 2.14. UseforkCount
e em seureuseForks
lugar. "Eu tive o mesmo problema, e a solução para mim foi permitir que o Maven tratasse de todas as dependências, incluindo jars locais. Usei o Maven para dependências online e configurei o caminho de construção manualmente para dependências locais. Portanto, o Maven não estava ciente das dependências que configurei manualmente.
Usei esta solução para instalar as dependências jar locais no Maven:
Como adicionar arquivos jar locais no projeto maven?
fonte
No meu caso, o motivo foi um bug no código. O teste contou com uma determinada ordem de elementos em a
HashSet
, que acabou sendo diferente quando executado no Eclipse ou no Maven Surefire.fonte
É mais provável que seus arquivos de configuração estejam em src / main / resources , enquanto devem estar em src / test / resources para funcionar corretamente no maven.
https://cwiki.apache.org/UIMA/differences-between-running-unit-tests-in-eclipse-and-in-maven.html
Estou respondendo isso depois de dois anos porque não consegui encontrar essa resposta aqui e acho que é a certa.
fonte
src/main/resources
está visível para os testes, massrc/test/resources
não para o código de produção.