我有一系列集成测试,我想测试我的spring-mvc / spring-data-jpa堆栈。不幸的是,构建时间很荒谬,每次新的集成测试都会变得更糟。看起来好像每个单独的测试都要经过创建嵌入式数据库,bean创建等的开销。
我有一个基础测试类:
@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 );
}
...}
在观看构建日志时,我可以看到每个测试的应用程序初始化。有没有办法让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(表“ADDRESSTYPEREF”没有 发现; SQL语句:
@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 :(得分: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 Profile,你不必在单独的xmls中分隔数据库。
清单-1:你的应用-context.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方法问题。是否在您的日志中创建了dataSource?