[java] JUnit 테스트는 Eclipse에서 통과하지만 Maven Surefire에서는 실패합니다.

JUnit 4 및 스프링 테스트 라이브러리를 사용하여 JUnit 테스트를 작성했습니다. Eclipse 내에서 테스트를 실행하면 정상적으로 실행되고 통과됩니다. 그러나 Maven을 사용하여 (빌드 프로세스 중에) 실행하면 스프링 관련 오류가 발생합니다. 문제의 원인이 JUnit, Surefire 또는 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



답변

나는 동일한 문제가 있었고 (JUnit 테스트는 Maven Surefire에서 실패했지만 Eclipse에서 통과했습니다) pom.xml의 maven surefire 구성에서 forkMode항상 설정하여 해결했습니다 .

<플러그인>
    <groupId> org.apache.maven.plugins </ groupId>
    <artifactId> maven-surefire-plugin </ artifactId>
    <버전> 2.12 </ 버전>
    <구성>
        <forkMode> 항상 </ forkMode>
    </ 구성>
</ 플러그인>

Surefire 매개 변수 : http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html

편집 (2014 년 1 월) :

으로 피터 Perháč는 지적의 forkMode 매개 변수는 확실한 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>

자세한 내용은 포크 옵션 및 병렬 테스트 실행을 참조하십시오.


답변

갑자기이 오류가 발생했고 해결책은 병렬 테스트 실행을 비활성화하는 것이 었습니다.

‘클래스’별로 병렬 테스트를 실행하도록 surefire를 구성하여 실패한 테스트의 수를 줄일 수 있으므로 마일리지가 다를 수 있습니다. :

            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.7.2</version>
                <configuration>
                    <parallel>classes</parallel>
                    <threadCount>10</threadCount>
                </configuration>
            </plugin>

내가 처음 쓴 것처럼 이것은 내 테스트 스위트에 충분하지 않았으므로 <configuration>섹션 을 제거하여 병렬을 완전히 비활성화했습니다 .


답변

비슷한 문제가 발생 @Autowired했습니다. 테스트 코드 의 주석은 Eclipse에서 제대로 작동하는 동안 Maven 명령 줄을 사용하여 작동하지 않았습니다. JUnit 버전을 4.4에서 4.9로 업데이트하고 문제가 해결되었습니다.

<dependency>
    <groupId>junit</groupId
    <artifactId>junit</artifactId>
    <version>4.9</version>
</dependency>


답변

이것은 귀하의 상황에 정확히 적용되지는 않지만 Maven의 테스트 목표가 실행될 때 Eclipse에서 통과 할 테스트가 실패했습니다.

다른 패키지 에서 내 스위트의 초기 테스트로 밝혀졌습니다. . 해결하는 데 일주일이 걸렸습니다!

이전 테스트에서는 일부 Logback 클래스를 테스트하고 구성 파일에서 Logback 컨텍스트를 생성했습니다.

이후의 테스트는 Spring의 SimpleRestTemplate의 서브 클래스를 테스트하는 것이었고, 어떻게 든 DEBUG가 켜진 상태에서 이전 Logback 컨텍스트가 유지되었습니다. 이로 인해 RestTemplate에서 HttpStatus 등을 기록하기 위해 추가 호출이 발생했습니다.

이 상황에 빠졌는지 확인하는 것은 또 다른 일입니다. Logback 테스트 클래스에 일부 Mocks를 주입하여 문제를 해결하여 실제 Logback 컨텍스트가 생성되지 않았습니다.


답변

비슷한 문제가 있지만 IntelliJ IDEA + Maven + TestNG + spring-test가 있습니다. ( 물론 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>


답변

다른 테스트 실행 결과 JUnit run로부터maven install 여러 가지 문제에 대한 증상 일 것으로 보인다.

테스트 실행을 재사용하는 스레드를 비활성화하면 우리의 경우에도 증상이 제거되었지만 코드가 스레드로부터 안전하지 않다는 인상은 여전히 ​​강력했습니다.

우리의 경우 차이는 테스트 동작을 수정 한 빈의 존재 때문이었습니다. JUnit 테스트 만 실행해도 괜찮지 만 프로젝트 실행install 대상을 테스트 케이스가 실패합니다. 개발중인 테스트 케이스 였기 때문에 즉시 의심 스러웠습니다.

그 결과 다른 테스트 케이스가 새로운 테스트 케이스가 실행될 때까지 존속 할 수있는 Spring을 통해 빈을 인스턴스화했습니다. 빈 존재는 일부 클래스의 동작을 수정하고 실패한 결과를 생성했습니다.

우리의 경우 해결책은 처음에는 필요하지 않은 콩을 제거하는 것이 었습니다 ( 복사 + 붙여 넣기 총 에서 또 다른 상을 받았습니다 ).

이 증상이있는 모든 사람에게 근본 원인이 무엇인지 조사 할 것을 제안합니다. 테스트 실행에서 스레드 재사용을 비활성화하면 숨길 수 있습니다.


답변

나는 같은 문제가 있었지만 나에게 문제는 Java assertion (eg assert (num> 0))이 Eclipse에서 활성화되지 않았지만 maven을 실행할 때 활성화되었다는 것입니다.

따라서 Eclipse에서 jUnit 테스트를 실행해도 어설 션 오류가 트리거되지 않았습니다.

jUnit 4.11 (내가 사용하던 이전 버전과 반대)을 사용할 때 이것은 어설 션 오류를 출력하기 때문에 명확 해집니다.

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)