2013-07-13 45 views
0

我有一系列的集成测试,我想测试我的弹簧mvc /弹簧数据jpa堆栈。不幸的是,构建时间很荒谬,而且每次新的集成测试只会变得更糟。它看起来就好像每个单独的测试会通创建嵌入数据库,bean创建等如何高效地创建基础测试类的弹簧mvc集成测试

我有一个基础测试类的开销:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { JpaConfig.class }) 
public class BaseItegration { 

private static EmbeddedDatabase database; 

@BeforeClass 
public static void setUp() throws Exception { 
    database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).setName("mydb") 
     .addScript("classpath:embeddedDatabase.sql").build(); 
} 


@Test 
    public void testInit() { 
     Assert.assertNotNull(database); 
    } 

凡我JpaConfig.java:

@Configuration 
@EnableTransactionManagement 
@ComponentScan(basePackages = { "org.myproject.service", "org.myproject.utility", 
     "org.myproject.controller", "org.myproject.utility.startup", 
     "org.myproject.security" }) 
@ImportResource({ "classpath:applicationContext.xml", "classpath:myproject-spring-security.xml" }) 
public class JpaConfig { 
@Bean 
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {...} 
    @Bean 
    public DataSource dataSource() {...} 

    <etc> 
} 

然后最后我尝试使用它,例如:

@TransactionConfiguration(defaultRollback = true) 
@Transactional(propagation = Propagation.NESTED) 
public class TestContactTypesIT extends BaseItegration { 

    @Autowired 
    private ContactTypeRefRepository contactTypeRepository; 
    @Test 
    public void testRepositoryNotNull() { 
     Assert.assertNotNull(contactTypeRepository); 
    } 

...} 

在观看布维ld日志,我可以看到每个测试的应用程序启动。有没有办法让BaseIntegrationTest只启动一个,每个测试都使用该应用程序上下文和嵌入数据库?

========

更新

我改变了我的JpaConfig这样:

@Bean 
public DataSource dataSource() { 
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).setName("mydb") 
       .addScript("classpath:embeddedDatabase.sql").build(); 
} 

和我BaseIntegration现在是空的:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { JpaConfig.class }) 
public abstract class BaseItegration { 

} 

这里是因为错误而失败的测试之一:

InvalidDataAccessResourceUsageException (Table "ADDRESSTYPEREF" not found; SQL statement:

@TransactionConfiguration(defaultRollback = true) 
@Transactional(propagation = Propagation.NESTED) 
public class TestSeedAddressTypesIT extends BaseItegration { 

    @Autowired 
    private AddressTypeRefRepository addressTypeRepository; 

    @Autowired 
    private SeedAddressTypes seedAddressTypes; 

    // hack because we can't do a BeforeClass with Autowired 
    private boolean seeded = false; 

    @Test 
    public void testRepositoryNotNull() { 
     Assert.assertNotNull(addressTypeRepository); 
    } 

    @Test 
    public void testPopulatedDB() { 
     if (!seeded) { 
      seedAddressTypes.seed(); 
      seeded = true; 
     } 
     List<AddressTypeRef> addressTypes = addressTypeRepository.findAll(); 
     Assert.assertEquals(5, addressTypes.size()); 

    } 
} 

然而,所有的集成测试似乎重新ApplicationContext的和嵌入式数据库。虽然构建日志不显示正在创建的数据源,但我确实看到每个集成测试都创建一个新的log4j文件,45个测试需要15分钟才能生成。

+0

AFAIK,不应该为每个测试重新创建spring上下文。你如何运行测试?你确定你没有配置测试运行器为每个测试产生一个新的JVM吗? –

+0

我正在使用“mvn clean verify”构建WAR文件。 – sonoerin

回答

2

看起来@BeforeClass表示任何使用@BeforeClass注释的静态方法在类中的任何测试方法之前运行。所以如果你有一个包含几个类的测试套件,它的运行次数与测试类的数量相同。

为什么不在独立的applicationContexts中初始化嵌入式数据库和真正的数据库并在测试中只添加嵌入式数据库applicationContext?

例如(对不起,我不熟悉java配置样式):

清单-1:嵌入式database.xml

<jdbc:embedded-database id="dataSource"> 
    <jdbc:script location="classpath:schema.sql"/> 
    <jdbc:script location="classpath:test-data.sql"/> 
</jdbc:embedded-database> 

清单-2:BaseItegration.java

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:your-application-without-a-real-database.xml", "classpath:"embedded-database.xml" }) 
public class BaseItegration { 


} 

然后用applicationContext启动嵌入式数据库(因此只有一次)。

另一个解决方案是使用Spring配置文件,您不必在单独的xmls中分离数据库。

清单1:你的应用程序上下文。XML

<bean profile="integrationTest"> 
    <jdbc:embedded-database id="dataSource"> 
     <jdbc:script location="classpath:schema.sql"/> 
     <jdbc:script location="classpath:test-data.sql"/> 
    </jdbc:embedded-database> 
<bean> 

<bean profile="production"> 
    //omitted 
</bean> 

上市-2:BaseItegration.java

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:your-application-context.xml" }) 
@ActiveProfiles("integrationTest") 
public class BaseItegration { 


} 

记住活动的产品在你的web.xml。

更新:

修改您的BaseIntegration作为抽象类来解决没有@Test方法问题。并且是在您的日志中创建的数据源?

+0

我修改了BaseItegration,以便它不再创建嵌入式数据库,还更改JpaConfig以创建嵌入式数据库作为数据源。但是现在我所有的集成测试都失败了,因为他们找不到数据库。我更改了我的问题以反映这些更改 – sonoerin

+0

@sonoerin已更新,并且可以发布您的BaseIntegration子类之一吗? – Hippoom

+0

我用抽象基类和示例测试更新了我的文章。我没有看到正在创建的数据源,但日志文件是在每次测试时创建的,85次测试的总体构建时间为15分钟。 – sonoerin