当前位置: 首页 > 面试题库 >

如何模拟要测试的数据库(Java)?

龙越彬
2023-03-14
问题内容

我正在用Java编程,而我的应用程序正在大量使用DB。因此,对我来说重要的是能够轻松测试数据库的使用情况。
什么是DB测试?对我来说,他们应该提供两个简单的要求:

  1. 验证SQL语法。
  2. 更重要的是,根据给定情况检查数据是否正确选择/更新/插入。

那么,看来我只需要一个DB。
但实际上,我不喜欢这样做,因为使用数据库进行测试几乎没有困难:

  • “只给自己一个测试数据库,这有多难?” -嗯,在我的工作场所,拥有个人测试数据库几乎是不可能的。您必须使用每个人都可以访问的“公共”数据库。
  • “这些测试肯定不会很快…”-DB测试往往比常规测试慢。进行缓慢的测试真的不理想。
  • “此程序应处理任何情况!” -在数据库中尝试模拟每种情况变得有些烦人,甚至是不可能的。对于每种情况,都应进行一定数量的插入/更新查询,这很烦人并且需要时间。
  • “请稍等,您怎么知道该表中有542行?” -测试的主要原则之一是能够以与测试代码不同的方式测试功能。使用DB时,通常有一种方法可以执行某项操作,因此测试与核心代码完全相同。

因此,您可以发现测试时我不喜欢DB(当然,在某些时候,我必须要解决这个问题,但是在发现大多数错误是通过使用其余的测试方法)。但是我在找什么呢?

我正在寻找一种使用文件系统或仅使用虚拟内存来模拟数据库,模拟数据库的方法。我以为可能有一个Java工具/软件包,可以允许每个测试简单地(使用代码接口)构造一个数据库模拟,模拟表和行,SQL验证以及用于监视其状态的代码接口(而不是使用SQL)
)。

您熟悉这种工具吗?

编辑: 感谢您的答案!尽管我在寻找工具,但您也向我提供了有关该问题的提示:)我将花一些时间检查您的报价,因此,现在无法确定您的答案是否令人满意。

无论如何,这是我正在寻找的更好的视图-
想象一下一个名为DBMonitor的类,它的功能之一就是查找表中的行数。这是我想如何使用JUnit测试该功能的虚构代码:

public class TestDBMonitor extends TestCase {

    @Override
    public void setUp() throws Exception {

       MockConnection connection = new MockConnection();

       this.tableName = "table1";
       MockTable table = new MockTable(tableName);

       String columnName = "column1";
       ColumnType columnType = ColumnType.NUMBER;
       int columnSize = 50;
       MockColumn column = new MockColumn(columnName, columnType, columnSize);
       table.addColumn(column);

       for (int i = 0; i < 20; i++) {
           HashMap<MockColumn, Object> fields = new HashMap<MockColumn, Object>();
           fields.put(column, i);
           table.addRow(fields);
       }

       this.connection = connection;
    }

    @Test
    public void testGatherStatistics() throws Exception {

       DBMonitor monitor = new DBMonitor(connection);
       monitor.gatherStatistics();
       assertEquals(((MockConnection) connection).getNumberOfRows(tableName),
                    monitor.getNumberOfRows(tableName));
    }

    String tableName;
    Connection connection;
}

我希望这段代码足够清楚,可以理解我的想法(对我来说,语法错误,请输入我没有亲爱的Eclipse:P的手动代码)。

顺便说一下,我部分使用ORM,而我的原始SQL查询非常简单,并且在一个平台与另一个平台之间应该没有什么不同。


问题答案:

对旧问题的新答案(但情况有所发展):

如何模拟要测试的数据库(Java)?

您不会模拟它。您嘲笑您的存储库,但不对其进行测试,或者在测试中使用相同的数据库,然后对sql进行测试。所有内存数据库都不完全兼容,因此它们不会为您提供全面的覆盖范围和可靠性。永远不要尝试模拟/模拟连接,结果集等深层db对象。它根本没有任何价值,是开发和维护的噩梦

拥有个人测试数据库几乎是不可能的。您必须使用一个“公共”数据库,每个人都可以使用

不幸的是,许多公司仍然使用该模型,但是现在我们有了docker,几乎每个数据库都有映像。商业产品有一些局限性(例如,高达几GB的数据)对于测试而言并不重要。您还需要在此本地数据库上创建架构和结构

“这些测试肯定不会很快…”-DB测试往往比常规测试慢。进行缓慢的测试真的不理想。

是的,数据库测试速度较慢,但​​并不是那么慢。我做了一些简单的测量,一个典型的测试用了5-50ms。需要时间的是应用程序启动。有很多方法可以加快速度:

  • 第一个DI框架(例如spring)提供了仅运行应用程序某些部分的方式。如果您编写的应用程序将db和与db无关的逻辑很好地分开,那么在您的测试中,您只能启动db部分
  • 每个数据库都有大量的调优选项,使其耐用性降低,速度更快。非常适合测试。postgres的例子
  • 您也可以将整个数据库放入tmpfs

  • 另一个有用的策略是设置测试组,并在默认情况下关闭数据库测试(如果它们确实减慢了构建速度)。这样,如果某人实际上正在处理db,则需要在cmd行中传递其他标志或使用IDE(testng组和自定义测试选择器非常适合此操作)

对于每种情况,都应进行一定数量的插入/更新查询,这很烦人并且需要时间

上面讨论了“花时间”部分。讨厌吗 我看过两种方法:

  • 为所有测试用例准备一个数据集。那么您必须维护它并对此进行推理。通常它与代码分开。它具有千字节或兆字节。在一个屏幕上看到,理解和推理是很大的。它引入了测试之间的耦合。因为当您需要更多行用于测试A时,您count(*)的测试B会失败。它之所以增长是因为即使删除了一些测试,您也不知道该测试仅使用了哪些行
  • 每个测试准备其数据。这样,每个测试都是完全独立,可读且易于推理的。讨厌吗 imo,一点也不!它使您可以非常快速地编写新测试,并节省了以后的工作量

您怎么知道该表中有542行?”-测试的主要原则之一就是能够以与测试代码不同的方式测试功能

嗯…不是真的。主要原理是检查您的软件是否响应特定输入生成了所需的输出。因此,如果您拨打dao.insert542次,然后dao.count返回542,则表示您的软件按指定方式工作。如果需要,可以在两者之间调用提交/删除缓存。当然,有时您想测试实现而不是合同,然后检查dao是否更改了数据库的状态。但您始终使用sql
B测试sql A(插入vs选择,序列next_val vs返回值等)。是的,您始终会遇到“谁将测试我的测试”的问题,答案是:没有人,因此请保持简单!

其他可能帮助您的工具:

  1. testcontainers将帮助您提供真实的数据库。

  2. dbunit-将帮助您清除测试之间的数据

缺点:

* 创建和维护架构和数据需要大量工作。特别是在您的项目处于密集开发阶段时。
* 这是另一个抽象层,因此,如果您突然想使用此工具不支持的某些数据库功能,可能很难对其进行测试
  1. testegration-旨在为您提供完整的,随时可用的和可扩展的生命周期(公开:我是创作者)。

缺点:

* 仅针对小型项目免费
* 非常年轻的项目
  1. 飞路或liquibase -数据库迁移工具。它们可以帮助您轻松地在本地db上创建架构和所有结构以进行测试。


 类似资料:
  • 由于一个人在单元测试和模拟之前没有经验,我使用Mockito学习了关于JUnit的初学者教程,并进行了一些实践。 现在,我需要对一些在MySQL数据库上执行基本数据库操作的类方法进行单元测试。我不想对数据库进行真正的更改。 在不访问真实数据库的情况下,是否存在验证类似方法的方法?还是我误解了单元测试和嘲笑的概念?

  • 问题内容: 我对Spring还是很陌生,想知道如何创建使用模拟数据源的JUnit测试以及如何在其中使用JNDI上下文?当前,我的应用程序使用来自tomcat的JNDI上下文来检索连接,并通过该连接从数据库中检索数据。所以我想我需要模拟JNDI调用和数据检索。关于解决此问题的最佳方法的任何很好的指示都是很棒的!非常感谢! 问题答案: 我通常在单独的文件中定义我的JNDI依赖项,例如: 这样,在测试资

  • 我正在尝试对服务方法进行单元测试。服务方法调用spring数据存储库方法来获取一些数据。我想模拟这个存储库调用,并自己提供数据。如何做到这一点?在Spring Boot文档之后,当我模拟存储库并在测试代码中直接调用存储库方法时,模拟工作正常。但是,当我调用服务方法时,反过来调用存储库方法,mocking就不起作用了。下面是示例代码: 服务级别: 测试等级:

  • 我想测试一个注入数据源bean的类,但我不知道如何模拟bean数据源(我没有类,只有bean配置)。我的班级是这样的: 我的豆子:

  • 问题内容: 我有一个Java命令行程序。我想创建JUnit测试用例以进行模拟。因为当我的程序运行时,它将进入while循环并等待用户输入。如何在JUnit中模拟呢? 问题答案: 从技术上讲,可以进行切换,但是总的来说,不直接在代码中调用它,而是添加一层间接层,这样输入源就可以从应用程序的某个位置进行控制,这样会更健壮。确切地讲,这是实现的详细信息-依赖项注入的建议很好,但是你不一定需要引入第三方框

  • 已删除MyTestConfig.class,但问题仍然相同。即使我使用@SpringBootTest(classes={Application.Class,MyProblematicServiceImpl.Class}),它仍然在自动连线的地方返回模拟对象。MyProblematicServiceImpl是用@Service注释的空类。