Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 如何在不影响数据库的情况下测试服务?_Database_Spring_Testing_Rollback - Fatal编程技术网

Database 如何在不影响数据库的情况下测试服务?

Database 如何在不影响数据库的情况下测试服务?,database,spring,testing,rollback,Database,Spring,Testing,Rollback,我正在为Spring中的应用程序编写一些集成测试。我想测试一些服务,但它们可能会调用一些数据访问对象,新数据将保存在我的数据库中。在测试完成后,我有两种方法可以清除数据库中的每一项内容: 使用临时数据库在那里插入测试数据 每次我做测试都要清理所有的表格 然而,我正在寻找一种干净、向前的方法,这样我就可以不用手动清理就可以使用我的数据库。有什么想法吗 还有另一种选择:在测试服务时,对DAO使用mock 单元测试不同于集成测试。单元测试应该只关注感兴趣的类,而不是它的所有依赖项 我假设您已经以事务方

我正在为Spring中的应用程序编写一些集成测试。我想测试一些服务,但它们可能会调用一些数据访问对象,新数据将保存在我的数据库中。在测试完成后,我有两种方法可以清除数据库中的每一项内容:

  • 使用临时数据库在那里插入测试数据
  • 每次我做测试都要清理所有的表格

  • 然而,我正在寻找一种干净、向前的方法,这样我就可以不用手动清理就可以使用我的数据库。有什么想法吗

    还有另一种选择:在测试服务时,对DAO使用mock

    单元测试不同于集成测试。单元测试应该只关注感兴趣的类,而不是它的所有依赖项

    我假设您已经以事务方式对DAO进行了单元测试,因此无需再次证明它们工作正常

    您没有提到的集成测试的另一个选项是使来自服务的所有数据库交互都是事务性的。执行这些操作,完成后将其回滚


    临时数据库是一个很有吸引力的选择。您可以使用一些小而轻的东西,如高超音速、德比或SQLLite。缺点是您必须更新模式两次:一次在测试数据库中,一次在生产实例中。无论如何,如果你必须这样做,那就太糟糕了。

    对问题的评论做出回答,因为仅仅一条评论无法捕捉到它

    在每次测试之间建立和拆除数据库对于性能来说无疑是非常昂贵的。如何进行完全取决于数据库本身。(mssql、MySQL、PostgreSQL等)如果您可以在使用相同代码的情况下交换一个完全在内存中的数据库,那么这将是每次测试中设置和拆除的最快的数据库

    例如,我曾经有一个项目,需要对MS SQL实例运行测试。安装和拆卸大大降低了测试的速度,但我们都认为扩展测试覆盖范围是值得的。(我们每晚运行集成测试,而不是在签入时运行,所以这也没什么大不了的。)为了完全刷新数据库,我们使用了以下代码(C#,抱歉):

    然后在测试的配置中,我们有三个值:

  • 数据库的连接字符串
  • 用于MS SQL执行安装/拆卸的命令行可执行文件
  • 可执行文件用于执行设置的SQL包文件
  • 因此,在每次测试之前,我们都会运行此命令,根据源代码管理中的SQL包将数据库完全刷新到已知的初始状态。同样,这是非常缓慢,但它的工作。可能会有更快的解决方案适合您。(可能不是删除并重新创建数据库,而是截断并重新填充表,或者删除并重新创建表等。对其进行修补,以找到适合您需要的功能。)

    此外,我们希望确保它适合我们的领域模型,而不会污染SQL依赖之外的任何东西。我们用于数据访问的模型是存储库模式。基本上,我们的中心域代码具有域模型(不与DB表或任何其他依赖项耦合)和这些模型的存储库接口。然后,一个数据访问项目实现了这些接口,并在域模型和数据库表/列之间进行了内部映射

    (对于相同的接口,我们还有另外两个存储库实现项目。一个是用于域单元测试的内存中实现。它只保留发送到存储库的模型的静态列表。另一个是在没有SQL实例的情况下,使用每个数据持久性的XML文件来运行软件的实现。在由依赖项注入容器的配置设置确定应用程序的任何给定实例是否使用了e。)

    因此,我们所做的是在域中添加另一个名为
    DataResetter
    的接口。然后每个数据访问实现(SQL、内存中、XML)都实现了该接口。SQL使用上述代码和配置值,内存中的只清除了静态列表,XML的只删除了XML文件

    这允许测试将域功能用于测试设置和拆卸,并允许依赖项注入容器确定要使用的实现。这样,测试就不会与任何特定的实现耦合。这样做的另一个好处是,相同的测试可以用于单元和集成目的它们之间的区别只不过是一个配置设置


    (首先测试整个域是否与内存中的模拟实现一起工作,然后使用一个依赖项实现再次测试域,再使用另一个实现再次测试域,等等。我们最终在整个系统中为十几个不同的依赖项实现每晚运行同一组测试十几次。一次一个依赖项。这让我们很容易地看到什么东西坏了,因为在任何给定的测试运行中,只有一个新变量。)

    还有另一个选项:事务回滚


    根据您打开和提交事务的方式,您可能不提交事务,而是返回角色。

    如果您使用的是Spring框架,那么我认为您应该已经检查了Spring的测试方法。

    您将看到Spring将使它变得如此简单,您不需要直接与事务交互。您只需要在测试顶部添加一个@Transactionl注释,那么使测试具有事务性有什么好处呢?是的!正如前面其他答案所述,它将允许您回滚您的事务sactions,因此数据库中不会保留任何内容。请查看以下示例代码:

        @Transactional
        public class FictitiousTransactionalTest {
    
            @Before
            public void setUpTestDataWithinTransaction() {
                // set up test data within the transaction
            }
    
            @Test
            @Rollback(true)
            public void modifyDatabaseWithinTransaction() {
                // logic which uses the test data and modifies database state
            }
        }
    
    我需要注意一些重要的事情
        @Transactional
        public class FictitiousTransactionalTest {
    
            @Before
            public void setUpTestDataWithinTransaction() {
                // set up test data within the transaction
            }
    
            @Test
            @Rollback(true)
            public void modifyDatabaseWithinTransaction() {
                // logic which uses the test data and modifies database state
            }
        }