如何使用有状态的Python模块正确实现测试隔离?

Luk*_*404 8 python state unit-testing code-structure

我正在研究的项目是一个包装为Python包的业务逻辑软件.这个想法是各种脚本或应用程序将导入它,初始化它,然后使用它.

它目前有一个顶级的init()方法,用于初始化和设置各种事物,一个很好的例子是它使用数据库连接设置SQLAlchemy并存储SA会话以供以后访问.它存储在我的项目的子包中(即myproj.model.Session,因此其他代码可以在导入模型后获得有效的SA会话).

长话短说,这使我的包装成为有状态的.我正在为项目编写单元测试,这种安全行为会带来一些问题:

  1. 应该隔离测试,但是我的包的内部状态打破了这种隔离
  2. 我无法测试主init()方法,因为它的行为取决于状态
  3. 未来的测试需要针对具有众所周知的模型状态的(尚未编写的)控制器部分运行(例如,预先填充的sqlite 内存数据库)

我应该以某种方式重构我的包,因为当前的结构不是最好的(可能的)练习(tm)?:)

我应该把它留在那里,每次安装/拆除整件事吗?如果我要实现完全隔离,这意味着在每次测试中完全擦除并重新填充数据库,那不是太过分了吗?

这个问题实际上是关于整体代码和测试结构的,但是对于我的测试我使用nose-1.0的价值.我知道Isolate插件可能对我有所帮助,但我想在测试套件中做一些奇怪的事情之前得到正确的代码.

die*_*dha 3

您有几个选择:

模拟数据库

有一些权衡需要注意。

您的测试将变得更加复杂,因为您必须进行连接的设置、拆卸和模拟。您可能还想验证发送的 SQL/命令。它还往往会产生一种奇怪的紧密耦合,这可能会导致您在架构或 SQL 更改时花费额外的时间来维护/更新测试。

这通常是最纯粹的测试隔离,因为它减少了测试的潜在巨大依赖性。它还往往会使测试更快,并减少在持续集成环境中自动化测试套件的开销。

每次测试时重新创建数据库

需要注意的权衡。

这可能会使您的测试非常慢,具体取决于重新创建数据库实际花费的时间。如果开发数据库服务器是共享资源,则必须进行额外的初始投资以确保每个开发人员在服务器上拥有自己的数据库。服务器可能会受到影响,具体取决于测试运行的频率。在持续集成环境中运行测试套件会产生额外的开销,因为它至少需要,可能更多的数据库(取决于同时构建的分支数量)。

好处与实际运行将在生产中使用的相同代码路径和类似资源有关。这通常有助于尽早发现错误,这总是一件非常好的事情。

ORM 数据库交换

如果您使用像 SQLAlchemy 这样的 ORM,您可以将底层数据库替换为可能更快的内存数据库。这可以让您减轻前两个选项的一些负面影响。

它与生产中使用的数据库并不完全相同,但 ORM 应该有助于减轻掩盖错误的风险。通常,设置内存数据库的时间比文件支持的数据库要短得多。它还具有与当前测试运行隔离的好处,因此您不必担心共享资源管理或最终拆卸/清理。