Тесты JUnit проходят в Eclipse, но не проходят в Maven Surefire - PullRequest
80 голосов
/ 29 июля 2010

Я написал несколько тестов JUnit с использованием библиотек JUnit 4 и spring-test.Когда я запускаю тесты внутри Eclipse, тогда все работает нормально и проходит.Но когда я запускаю их с помощью Maven (в процессе сборки), они не дают ошибку, связанную с пружиной.Я не уверен, что является причиной проблемы, JUnit, Surefire или Spring.Вот мой тестовый код, конфигурация Spring и исключение, которое я получаю от 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>

Исключение в 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

Ответы [ 16 ]

88 голосов
/ 22 марта 2012

У меня была та же проблема (тесты JUnit не прошли в Maven Surefire, но прошли в Eclipse), и мне удалось ее решить, установив forkMode в всегда в конфигурации maven верный в 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: http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html

Изменить (январь 2014 г.):

Как указал Петер Перхач , параметр forkMode устарел с Surefire 2.14. Начиная с Surefire 2.14 используйте это вместо:

<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>

Для получения дополнительной информации см. Параметры вилки и выполнение параллельного теста

7 голосов
/ 13 марта 2012

У меня была похожая проблема, аннотация @Autowired в тестовом коде не работала при использовании командной строки Maven, хотя в Eclipse работала нормально Я просто обновил свою версию JUnit с 4.4 до 4.9, и проблема была решена.

<dependency>
    <groupId>junit</groupId
    <artifactId>junit</artifactId>
    <version>4.9</version>
</dependency>
7 голосов
/ 26 сентября 2011

Я внезапно столкнулся с этой ошибкой, и решение для меня состояло в том, чтобы отключить параллельное выполнение тестов.

Ваш пробег может отличаться, так как я мог бы уменьшить количество неудачных тестов, настроив верный запуск параллельных тестов по классам.для моего набора тестов, поэтому я полностью отключил параллель, удалив раздел <configuration>.

5 голосов
/ 26 июля 2011

У меня похожая проблема, но с IntelliJ IDEA + Maven + TestNG + spring-test. ( весенний тест необходим, конечно, :)) Это было исправлено, когда я изменил конфигурацию maven-surefire-plugin , чтобы отключить параллельное выполнение тестов. Как это:

<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>
4 голосов
/ 20 января 2012

Это не совсем относится к вашей ситуации, но у меня было то же самое - тесты, которые должны были пройти в Eclipse, не были выполнены при выполнении цели теста от Maven.

Оказалось, что это тестранее в моем номере в другой упаковке .Это заняло у меня неделю, чтобы решить!

Предыдущий тест проверял некоторые классы Logback и создавал контекст Logback из файла конфигурации.

Более поздний тест проверял подкласс SpringRestTemplate Springи каким-то образом, более ранний контекст Logback был сохранен, с включенным DEBUG.Это вызвало дополнительные вызовы в RestTemplate для регистрации HttpStatus и т. Д.

Это еще одна вещь, чтобы проверить, попадет ли кто-нибудь в эту ситуацию.Я исправил свою проблему, добавив несколько Mocks в мой тестовый класс Logback, так что реальные контексты Logback не создавались.

3 голосов
/ 04 октября 2017

Результат выполнения теста, отличный от JUnit run и от maven install, кажется симптомом нескольких проблем.

Отключение повторного использования потока в тесте также избавило от симптома в нашем случае, но впечатление, чтокод не был ориентирован на многопоточность и был по-прежнему силен.

В нашем случае различие было связано с наличием компонента, который изменил поведение теста.Выполнение только теста JUnit приведет к хорошему результату, но выполнение цели проекта install приведет к неудачному тестовому варианту.Поскольку этот тестовый пример находился в стадии разработки, он сразу был подозрительным.

Это привело к тому, что в другом тестовом примере был создан экземпляр объекта через Spring, который сохранится до выполнения нового тестового примера.Присутствие bean-компонентов изменяло поведение некоторых классов и приводило к неудачному результату.

В нашем случае решением было избавиться от bean-компонента, который не был необходим в первую очередь (еще один приз от * 1012).* copy + paste gun).

Я предлагаю всем, у кого есть этот симптом, выяснить, в чем причина.Отключение повторного использования потока при выполнении теста может только скрыть его.

3 голосов
/ 23 февраля 2017

У меня была похожая проблема с другой причиной и, следовательно, с другим решением.В моем случае у меня действительно была ошибка, когда у одноэлементного объекта была переменная-член, измененная не-потокобезопасным способом.В этом случае, следуя принятым ответам и обходя параллельное тестирование, можно будет скрыть только ту ошибку, которая была фактически обнаружена тестом.Мое решение, конечно, состоит в том, чтобы исправить дизайн так, чтобы у меня не было такого плохого поведения в моем коде.

3 голосов
/ 21 января 2013

У меня была та же проблема, но проблема для меня заключалась в том, что утверждения Java (например, assert (num> 0)) не были включены для Eclipse, но были включены при запуске maven.

Поэтому выполняется jUnitтесты от Eclipse не перехватили триггер ошибки подтверждения.

Это становится ясно при использовании jUnit 4.11 (в отличие от предыдущей версии, которую я использовал), потому что она печатает ошибку подтверждения, например,

* 1006.*
2 голосов
/ 26 октября 2013

У меня была похожая проблема: тесты JUnit не прошли в Maven Surefire, но прошли в Eclipse, когда я использовал библиотеку JUnit версии 4.11.0 из репозитория SpringSource Bundle.Particulary:

<dependency>
    <groupId>org.junit</groupId>
    <artifactId>com.springsource.org.junit</artifactId>
    <version>4.11.0</version>
</dependency>

Затем я заменил его на следующую библиотеку JUnit версии 4.11, и все работает нормально.

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>
2 голосов
/ 23 марта 2012

[Я не уверен, что это ответ на первоначальный вопрос, так как трассировка стека здесь выглядит немного иначе, но может быть полезна для других.]

Вы можете получить тесты, терпящие неудачу в Surefire, когда вытакже работают Cobertura (чтобы получить отчеты о покрытии кода).Это потому, что Cobertura требует прокси (для измерения использования кода), и между ними и Spring прокси существует какой-то конфликт.Это только происходит, когда Spring использует cglib2, что будет иметь место, если, например, у вас есть proxy-target-class="true", или если у вас есть объект, который проксируется, который не реализует интерфейсы.

Нормальным решением проблемы является добавление интерфейса.Так, например, DAO должны быть интерфейсами, реализованными классом DAOImpl.Если вы автоматически подключитесь к интерфейсу, все будет работать нормально (потому что cglib2 больше не требуется; вместо него можно использовать более простой JDK-прокси для интерфейса, и Cobertura прекрасно с этим работает).с аннотированными контроллерами (при попытке использовать контроллер в сервлете вы получите ошибку во время выполнения) - у меня нет решения для тестов Cobertura + Spring с автопроводкой контроллеров.

...