Python 烧瓶炼金术的实单元测试

Python 烧瓶炼金术的实单元测试,python,unit-testing,sqlalchemy,Python,Unit Testing,Sqlalchemy,我在网上搜索“单元测试sqlalchemy”之类的关键词,但所有答案都涉及到创建真实的数据库(sqlite、postgres)来测试它。当你创建真实的东西时,这不是单元测试 创建sqlite DB与在磁盘上创建文件没有什么不同,但令人惊讶的是,人们只希望模拟后者。我尝试过使用setUp和sys.modules模拟db import,但效果很好,但模拟太多,使用模型作为测试对象也不简单(模拟不支持所有需要的东西,如next) 是否有任何技术可以模拟数据库行为(创建数据库、提交、查询),但仍然可以访

我在网上搜索“单元测试sqlalchemy”之类的关键词,但所有答案都涉及到创建真实的数据库(sqlite、postgres)来测试它。当你创建真实的东西时,这不是单元测试

创建sqlite DB与在磁盘上创建文件没有什么不同,但令人惊讶的是,人们只希望模拟后者。我尝试过使用setUp和sys.modules模拟db import,但效果很好,但模拟太多,使用模型作为测试对象也不简单(模拟不支持所有需要的东西,如next


是否有任何技术可以模拟数据库行为(创建数据库、提交、查询),但仍然可以访问模型对其进行基本检查?也许有一些库可以只模拟连接?

继我的“此Q将被关闭”之后,我相信没有一种权威的方法可以做到这一点,您需要选择如何模拟

基本上,SQLAlchemy是数据库设计和查询的抽象。这意味着,您可以将模型放置在抽象中的不同位置:

  • 真实数据库,带有测试数据
  • 您可以设置sqlite实例。此解决方案的优点是,您不需要调整/修补python堆栈中的任何内容,因为您正在更改系统前沿的内容,缺点是维护的工作量更大,因此风险更大

    • 使用数据文件
    并将这些数据文件作为资源存储在代码中。然后为正在运行的测试加载正确的db。您需要一个
    tearDown()
    方法在测试后将数据库恢复到其原始状态。 好的一面是,用很少的代码很容易实现,但是如果你修改你的模型,那就太麻烦了

    • 使用内存中的数据库
    在那里,您将数据填充到
    setUp()
    方法中,并且没有数据库可存储在git中或在代码之外处理。 尽管如此,您仍然需要维护大量的
    setUp()
    code

    碳纤维

    这一战略将是最常用和最明智的战略

  • 模拟数据库访问
  • 另一种方法,通常用于模拟HTTP连接,它是序列化SA和数据库之间通信的输出和输入。我不知道有哪个库会这样做,但这将是一件非常棒的事情

    基本上,只需想象一个JSON文件,其中包含发送到数据库的所有请求和从数据库返回的数据。每次播放测试时,您只是在重放JSON记录

    进行更改时,可以记录I/O交互并序列化它们。有点像图书馆

    这个策略将是我最喜欢的实现方法,但是必须有人为这样一个工具编写实现

  • 模拟/猴子补丁sqlalchemy的各个元素
  • 这将是痛苦和大量的工作,但仍有许多人尝试这种方法。但我想不出这样做的好理由,因为您的目标不是测试sqlalchemy,而是测试您自己的代码,最终您将模拟sqlalchemy的大部分内容

  • 代码中所有db交互的抽象

  • 如果所有db交互都是由您自己的代码中的接口抽象的,那么您可以用一个模型来替换该接口的实现,并断言您得到了正确的参数。好的一面是它很容易测试和维护。不过,我不建议这样做,因为这样你就不会检查你是否正确使用了SQLAlchemy库。

    嗨,你的问题太广泛了(可能的答案太多,没有一个权威的答案),因此不适合SO问题,所以很可能会被关闭。看来你没有阅读我问题的第一部分。创建任何真实的对象,即使在内存中也是不符合UT的。在UTs中,您不依赖于其他东西,甚至不依赖于同一类中的函数(即使是最简单的一行程序,也只需模拟它们)。所以我正在寻找第三点的具体答案——库或只模拟特定数据库的技术。不幸的是,烧瓶中的SQLalchemy似乎只在输入中做了很多事情,所以这对我来说很难找到答案。Flask已经完成了抽象,但是他们的测试模块也依赖于真实的DB对象。我确实读了你问题的第一部分,但是你不想在这里进行UT,你想要功能/回归测试。UT表示您正在测试函数
    f(x)→y
    您正在验证所有
    y
    s的
    x
    的所有可能值。这意味着您的函数没有副作用,而调用SQLAlchemy方法的测试函数意味着相当大的副作用。因此,如果您希望在代码中尽可能多地执行UT,您可以执行解决方案4,然后只在您自己的抽象和如何使用SA之间执行功能和/或回归测试,即#1。是的,我们最终完成了简单的接口,对调用进行抽象,因为维护和测试非常容易。你混淆了两件事——UT和集成/回归测试。我们不希望开发人员产生容器来进行测试。我们希望它保持简单-
    python setup.py test
    无处不在。我们有基于行为的单独测试,用于测试CI中的用户逻辑,但这是由不同的部门负责的,开发人员只关注编码/UTs。