代码之家  ›  专栏  ›  技术社区  ›  Ozgur Akcali

使用Django进行测试驱动开发

  •  1
  • Ozgur Akcali  · 技术社区  · 7 年前

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

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

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

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

    2 回复  |  直到 7 年前
        1
  •  1
  •   Roman-Stop RU aggression in UA    7 年前

    重要提示 :您描述的不是单元测试。它不测试一个单元。它测试了从DjangoURL连接、视图到模型的一大堆东西。这是集成测试。第二,不要创建一个使用外部API(或基本相同的测试客户机)来创建数据的测试,而是通过直接转到DB来检查实体是否已创建。这不好。如果通过某个API创建数据,则应使用同一级别的API检查数据是否已创建。所以我的解释将讨论这种方法。

    你所描述的是一个常见的问题,当你开始与TDD。

    TDD的重要之处在于:

    1. 小步走

    这听起来可能很简单,而且你很可能已经读过并且知道这一点,但是你如何组织你的工作的后果可能并不那么明显。

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

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

    之前 您实现了生产代码而不是之后。

    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连接和空视图

    这样做使测试通过。您只需要对代码进行很少的更改,视图也不会返回太多内容。视图此时可以返回一些硬编码的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()))
    

    您可以通过向硬编码的dict中添加id来进行此测试。

    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的模型并从视图中添加其创建和检索并不困难。不要添加所有需要的字段,稍后将逐步添加。

    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

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

    对于一个TDD循环来说,步骤4可能太大。它至少需要对三件事做出改变:

    1. 后置视图处理程序
    2. 获取视图处理程序

    在许多情况下,首先为模型本身创建一个测试来拆分它是有意义的。无法与测试客户端一起工作的测试将如下所示:

    def test_entity(self):
        entity = Entity.objects.create()
    
        entity = Entity.objects.get(entity.id)
    
        assert_that(entity.id, not_none())
    

    然后添加一个模型。确保 test_entity

    我希望这能提供解决这个问题的方法。

        2
  •  0
  •   Marco Visibelli    7 年前

    在Django中,方法始终是重新创建用于测试和暂存的工作环境。在测试数据是假的,在暂存数据是“旧”或非常类似的生产。