如何比较预期和实际的数据库状态?

问题描述 投票:0回答:1

开始之前 这个问题看起来比较大,所以你可以浏览一下当前的方法,然后直接进入问题,在问题末尾用粗体标记。

我正在为项目中的一些处理程序编写测试。主要功能之一是在数据库中创建/更改/删除对象。

由于某些原因,我们不想编写代码来用某些逻辑来断言数据库中的突变(例如,在函数完成后,应该创建一个对象,该对象应该包含这样的字段值,让我们获取其创建的 id,然后看看,它的还创建了依赖项。另外,让我们检查是否没有删除其他对象,等等)

为了现在断言正确的数据库突变,我们使用以下方法:

  1. 内容直接比较

我们有加载所有当前数据库内容的功能

def get_db_content():
    result = []
    for table in TABLE_NAME_LIST:
         rows = db.fetch(f"SELECT * FROM {table}")
         for row in rows:
             result.append({"tablename": table, "fields": row})
    return result

创建列表,其中每个条目都包含表名,每个字段都具有特定对象的值。

此外,我们还有包含预期状态的 json 编码数据的夹具数据文件:

[
    {
        "tablename": "users",
        "fields": {
            "id": 1,
            "name": "Valt25"
        }
    }
]

在编写测试时,我们需要准备这样的夹具,并带有预期的数据,并进行基本比较:

assert get_db_content() == load_fixture("expected_db_state.json")

这很好用,如果我们在排序方面遇到问题,我们可以在 sql 中添加显式排序。

正如您在预期的数据库状态中看到的,用户 id 是一个整数值,很可能是串行的,我们无法事先知道这个值,幸运的是我们使用 uuid,在处理程序运行时生成。我们可以模拟 uuid 生成器函数,以期望数据库中具有特定 id 的新对象。

但是,我想不再在运行时生成东西,这些东西可能是在数据库级别生成的(例如uuid、创建/更新的日期戳),因此在比较过程中无法获得期望的某些数据。

为了解决这个问题,我们有下一个方法(实际上是修改第一个方法):

  1. 部分内容直接比较

我们有部分比较内容的辅助函数。因此,如果某些字段出现在数据库中,但未出现在预期数据中,那么就可以了。

所以现在,

get_db_content()
调用将返回下一个结果:

[
    {
        "tablename": "positions",
        "fields": {
            "id": 127,
            "name": "position name",
            "date_created": "2025-01-01T17:52:21"
            "date_updated": "2025-01-01T17:52:21"
        }
    },
    {
        "tablename": "employees",
        "fields": {
            "id": 256,
            "position_id": 127,
            "name": "user name",
            "date_created": "2024-12-31T10:45:21"
            "date_updated": "2025-01-01T17:52:21"
        }
    }
]

如您所见,此处预设了 id 和图章。但在赛程数据中我们有这样的东西:

[
    {
        "tablename": "positions",
        "fields": {
            "name": "position name"
        }
    },
    {
        "tablename": "employees",
        "fields": {
            "name": "user name"
        }
    }
]

正如您所看到的,没有任何自动生成的字段。下一行将成功断言:

assert partial_compare(get_db_content(), load_fixture("expected_db_state.json"))

问题从这里开始

正如您所看到的,以前的方法甚至可以在没有自动生成字段的情况下断言数据,但它不能断言数据库对象关系,但这是存储在任何地方的对象的相当重要的特征。为了克服这个问题,我们编写了相当复杂的代码,每个任务都是唯一的。

但是,我想以某种方式关联夹具文件中的对象。像这样的东西:

[
    {
        "tablename": "positions",
        "$tag": "created_position",
        "fields": {
            "name": "position name"
        }
    },
    {
        "tablename": "employees",
        "ref_fields": ["position_id"]
        "fields": {
            "position_id": "$created_position.id"
            "name": "user name"
        }
    }
]

如您所见,首先我用一些字符串标记位置。然后在员工对象中,我标记字段“position_id”不应通过值断言,但其值应从与指定标签关联的真实数据库对象中获取。并且还表明,“position_id”字段应与标有“created_position”标签的对象中的“id”字段相同。

问题本身

我确信我自己可以实现这样的事情,但是我预计这里会遇到很多陷阱。这就是为什么我写这个问题,也许有类似的方法,解决同样的问题,如果你不知道,也许你可以在这里看到陷阱?

PS。代码是用 python 编写的,但也可以是任何编程语言。

PS2。这里编写的任何代码都没有经过测试,因为它是为了展示方法而编写的,而不是为了实现特定功能。

python database testing automated-tests
1个回答
0
投票

不太确定实现这种数据库状态验证的最佳方法是什么。

首先想到的一件事是将从数据库接收到的数据加入某种聚合中:

SELECT employees.name AS name, positions.name AS position
FROM employees 
JOIN positions ON employees.position_id = positions.id;

然后将该数据与简单的预期值数组进行比较。例如

expected_employees.json

[
  {
    "name": "Michael Scott",
    "position": "Regional Manager"
  },
  {
    "name": "Dwight Schrute",
    "position": "Salesman"
  },
  ...
]

要验证数据库的完整状态,您可能需要多个不同的查询和相应的固定文件。

这种方法的一个优点是您可以保持实际的比较逻辑非常简单。如果排除自动生成的值,可能就像调用 Python 的

assertEqual
一样简单。

© www.soinside.com 2019 - 2024. All rights reserved.