python - 使用 Django 进行测试驱动开发

标签 python django testing tdd

我有一个关于使用 Django 进行测试驱动开发的概念性问题,也可能适用于其他框架。

TDD 指出开发周期的第一步是编写失败的测试。

假设对于一个单元测试,我想验证在请求到达时是否实际创建了一个项目。为了测试此功能,我想向测试客户端发出请求,并检查数据库是否实际创建了此对象。为此,我需要在测试文件中导入相关模型,但由于第一步是编写此测试,我什至还没有模型。所以我将无法运行测试以查看它们是否失败。

此处建议的方法是什么?也许先编写一个更简单的测试,然后在实现足够级别的生产代码后修改测试?

最佳答案

重要说明:您描述的不是单元测试。它不测试一个单元。它测试了从 django url 连接、 View 开始到模型结束的一大堆东西。这是集成测试。其次,不要创建使用外部 API(或大部分相同的测试客户端)来创建数据的测试,而是通过直接转到数据库来检查实体是否已创建。不是很好。如果您通过某些 API 创建数据,您应该使用相同级别的 API 来检查数据是否已创建。所以我的解释会讲到这个方法。

您描述的是开始使用 TDD 时的常见问题。

关于 TDD 的重要事项是您:

  1. 做小步骤
  2. 测试后重构是绿色的(包括测试重构)

这可能听起来很简单,您很可能已经阅读并知道,但对您的工作结构的影响可能并不那么明显。

主要后果是您没有在实现功能之前从头开始编写完整的测试。你从你能做的最简单的测试开始,让它工作(通过实现一些功能),重构。然后,您通过添加更多要检查的内容来更改测试,实现该部分以使测试绿色、重构等。

这导致您需要拆分工作(或计划如何通过简单的步骤实现它)才能在此模式下工作。这需要一些实践,我想这是采用 TDD 的主要障碍之一。

它与您写的内容相似(但有重要区别):

Maybe write a simpler test first, then modify the test after enough level of production code is implemented?

您需要先进行简单测试,然后用小步骤迭代修改它,但之前您实现生产代码而不是之后。

在这种特殊情况下,您可以按照以下步骤实现:

1 创建使用测试客户端的测试

def test_entity_creation(self):
    post_result = test_client.post(POST_URL, {})

    get_result = test_client.get(get_entity_url_from(post_result))

    assert_that(get_result, not_none())

您有一个失败的测试,但没有编写任何代码行。 请注意,尚未传递任何数据,并且检查非常基本。

2 创建url连接和空 View

这样做才能使测试通过。您只需要对代码进行很少的更改,并且 View 不会返回太多(如果有的话)。此时 View 可以返回一些硬编码的 json/dict。

3.1 检查实体id是否生成

def test_entity_creation(self):
    post_result = test_client.post(POST_URL, {})

    get_result = test_client.get(get_entity_url_from(post_result))

    assert_that(get_result, not_none())
    assert_that(get_result, has_field('id', not_none()))

您可以通过将 id 添加到硬编码的 dict 来使此测试正常进行。

3.1 检查实体的唯一id是否生成

添加一个检查 id 是否唯一的新测试:

def test_create_generates_unique_id(self):
    post_result1 = test_client.post(POST_URL, {})
    post_result2 = test_client.post(POST_URL, {})

    assert_that(get_id(post_result1), not_(equal_to(get_id(post_result2)))

4 添加只有id的模型

添加一个只有 id 的模型并从 View 中添加它的创建和检索并不难。不要添加您需要的所有字段,稍后您将逐步添加。

5 添加一个字段给你测试

def test_entity_creation(self):
    post_result = test_client.post(POST_URL, {'field': 'value'})

    get_result = test_client.get(get_entity_url_from(post_result))

    assert_that(get_result, not_none())
    assert_that(get_result, has_field('field', 'value'))

向模型中添加一个字段并使测试通过。

6 继续做 TDD

添加更多测试和生产代码。

一些想法

第 4 步对于一个 TDD 周期来说可能太大了。它至少需要改变三件事:

  1. 发布 View 处理程序
  2. 获取 View 处理器
  3. 模特

在许多情况下,通过首先为模型本身创建测试来拆分它是有意义的。不适用于测试客户端但看起来像这样的测试:

def test_entity(self):
    entity = Entity.objects.create()

    entity = Entity.objects.get(entity.id)

    assert_that(entity.id, not_none())

然后您添加一个模型。确保 test_entity 通过,并且只有在修改 View 之后才能使用您的(已经测试过的)模型。

我希望这能给出解决这个问题的想法。

关于python - 使用 Django 进行测试驱动开发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52389183/

相关文章:

django - 如何获取Queryset中所有对象的所有外键的Django QuerySet

django - 如何提高这个 django ORM 查询的性能?

java - 如何在运行时定义 JUnit 测试超时(即没有注释)?

python - 从应用程序引擎 python 中删除文件

python - .split() 和 .append 来自 .txt 文件的信息作为元组到新列表

django - 中间件是装饰器模式的实现吗?

testing - 你如何回应论点 "No time to test/develop clean code, because of the deadline"?

ruby-on-rails - 使用事件管理员进行 Rails 测试

python - 从数组中提取重复值和位置的列表

python - PYMC3 季节性变量