当前位置: 首页 > 知识库问答 >
问题:

如何高效地为spring mvc集成测试创建基础测试类

高朝明
2023-03-14

我有一系列的集成测试,我想用这些测试来测试我的spring-MVC/spring-数据-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只启动一个测试,并且每个测试都使用应用程序上下文和EmbeddedDatabase?

=========

我将我的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分钟来构建。

共有1个答案

逑和蔼
2023-03-14

似乎@BeforeClass意味着用@BeforeClass注释的任何静态方法在类中的任何测试方法之前运行。因此,如果您有一个包含多个类的测试套件,它运行的次数与您的测试类的数量一样多。

为什么不在seperate applicationContexts中初始化嵌入式数据库和真实数据库,并在测试中只添加嵌入式数据库applicationContext?

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

清单-1:embedded-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配置文件,您不必在分离的XML中分离数据库。

清单1:your-application-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方法的问题。数据源是否在日志中创建?

 类似资料:
  • 假设我有一个测试来断言系统中新用户的注册是否真的成功: 现在,这将在实际数据库中创建一个新的测试用户,因为我希望这个测试在实际环境中运行。这意味着测试不能一直运行,对吗?我应该如何进行此类测试?那些使用系统的实际环境并操纵真实数据的人?

  • 英文原文:http://emberjs.com/guides/testing/unit-testing-basics/ 尽管Ember.Object是Ember中得基础对象类型,然后能够测试一个简单的Ember.Object是能测试Ember应用各个特定部分的基础。如控制器、组件等。测试Ember.Object就如创建一个对象实例一样简单,设置其状态并针对对象进行断言。作为实例,下面将来介绍一些一

  • 英文原文:http://emberjs.com/guides/testing/integration/ 集成测试通常用来测试应用中得重要工作流。集成测试用来模拟用户交互和确认交互结果。 设置 为了对Ember应用进行集成测试,需要在测试框架中运行应用。首先需要将根元素(root element)设置为任意一个已知将存在的元素。如果根元素在测试运行时可见的话,这对测试驱动开发非常有用,带来的帮助非常

  • 我想用liquibase变更集进行模拟数据的集成测试,如何使其不影响真实数据库?我从这里找到了部分想法,但我使用的是springboot,我希望有更简单的解决方案。

  • 我想写一个集成测试,测试控制器的响应,只返回一个映射。通常,对于单元测试,这是按如下方式进行的 在集成测试中,这对我不起作用。还有别的方法吗? 问候语

  • 我想为类“ImageController”创建单元测试。由于映像必须由创建的用户拥有,所以我希望在执行单元测试之前创建一个用户(使用@before)。如何创建此用户?在测试UserController本身时,我做了如下操作: