是否应该模拟数据库连接



我正在尝试将单元测试应用于我正在从事的项目。我使用Python和MySQLdb,但我认为这个讨论与语言无关。我想测试一个函数,我们称之为 foobar()。它执行类似于以下内容的 SQL 查询:

cursor.execute("SELECT * FROM my_table WHERE a == " +varA+ " AND  b < " +varB)

函数中存在一些复杂性。cursor.execute(query)如何以及多久被召唤一次取决于foobar的论点。

现在我不确定我是否应该cursor模拟数据库连接。如果我不这样做,那就不好了,因为测试取决于数据库服务器的可用性。如果我这样做,那就不好了,因为模拟必须知道将调用哪些查询。但确切的查询是实现细节。例如,查询是小写还是大写并不影响foobar的正确性。但改变这一点会打破考验。由于模拟对象有些复杂,测试也将难以阅读。

这是选择较小的邪恶吗?还有第三种路吗?

不,您不应该模拟游标或连接。 重构代码并将此代码提取到单独的服务/存储库。 应该有一个方法,它接受两个参数varAvarB并返回行/对象列表

  • 在你的快速/单元测试中,你应该模拟整个存储库 - 检查你的方法是否使用正确的参数(varAvarB)调用。
  • 在慢速/集成测试中,您应该检查您的真实数据库是否正确执行此查询,以应对所有可能varAvarB

通过模拟连接/游标,您所做的只是简单地实现数据库 - 这只是浪费时间

您已经很好地权衡了这里的利弊,但需要注意的一点是,测试的目的是模拟尽可能接近生产中将看到的确切条件。

您应避免模拟数据库连接,并让它从本地 MysQL 数据库实例读取。此外,请确保在每次测试之前重置数据库的状态,以确保测试模块化。

一般工作流程是 -

  1. 在所有测试之前,myApp_test架构(如果尚不存在)。
  2. 删除所有表,然后从模拟数据固定装置重新创建它们。您可以通过多种方式执行此操作,我最喜欢的是从 YML 配置文件中读取夹具并将它们直接插入数据库。(如果你正在使用像rails这样的框架,它有预先构建的功能来做到这一点,或者有很多其他语言的gem和库可以帮助解决这个问题。
  3. 在每次测试之前,调用步骤 2 中的函数以重置数据库
  4. 运行测试

为了回应您的担忧,我认为它不依赖于可用的数据库,尤其是本地。如果您正在运行测试,则指定您应该有一个可用的数据库并非不合理。或者,如果您真的担心数据库的可用性,您可以尝试使用 SQLite 或其他基于文本的本地数据库在本地创建自己的数据库。

最新更新