【问题标题】:Trying to learn TDD - not going so well尝试学习 TDD - 不太顺利
【发布时间】:2012-05-10 13:58:18
【问题描述】:

我已经尝试学习 Python 大约 6 周了。在这个网站上阅读了很多关于 TDD 的内容后,我购买了 Roy Osherove 的 The Art of Unit Testing(很棒的书!),在学习 Python 的同时尝试和试验 TDD。这本书使用.NET,但似乎没有问题。存根就是存根,模拟就是模拟。

当我在网上阅读和查看 TDD 示例时,我真的觉得我明白为什么编码员会像他们那样编写代码。但是一旦我坐下来尝试自己,我一无所获。

让我给你举个昨天的例子:

我想为一个不太复杂的项目尝试 TDD。基本上,我想要的是一个类,它通过下载和解析 RSS 提要,保存一个包含(名称、日期)的元组列表。我为我的测试创建了一个新的 py 文件(还没有编写“真正的代码”)并编写了一个测试用例:

import unittest

from tv_schedule import TvSchedule

class TvScheduleTests(unittest.TestCase):
    def test_download_success_and_parse_failure(self):
        '''Successfully download RSS schedule for the specific user
           but fail parsing it'''
        self.tv = TvSchedule("User123")
        # Check if ParserException was thrown I guess


if __name__ == "__main__":
    unittest.main()

...然后我有点卡住了。我认为(大声笑!)。我真的需要一些关于这是否只是愚蠢和/或我如何才能做得更好的指示。我的直觉告诉我我做了坏事。

我想让 TvSchedule 类在后台进行下载/解析(使用feedparser),因此您只需创建该类的一个新实例,然后就可以使用它。也许这是糟糕的设计,也很难测试?另外,我将如何消除对通过网络检索 rss 提要的依赖?通过存根并始终返回包含示例提要的内存字符串?

一旦我离开了 TDD 教程和书籍喜欢使用的非常简单的计算器示例,我就陷入了困境。 :(

【问题讨论】:

  • 我认为同时学习 Python TDD 可能是个坏主意。 TDD 很棘手,可以在不添加新语言的情况下掌握窍门 :)
  • 请注意,“纯”TDD 仅在您对代码的使用方向有很好的了解时才能很好地工作。您可能想开始编写足够多的代码来巩固您的想法,然后为它编写一个测试(这应该会消除您尚未解决的任何问题),然后修复您的代码。
  • @kigurai:可能是这样。我想我会尝试的。有些人似乎认为 TDD 思维模式更容易进入,而缺乏传统思维模式。

标签: python tdd


【解决方案1】:

您可能遇到的一个挑战是您的测试过于广泛。一次下载和解析意味着您将编写大量代码。尝试将第一个测试压缩一点。这可能会帮助您集中注意力。

另一个挑战可能是您编写的代码没有太多逻辑,您只是委托其他库进行下载和 RSS 解析。这使得很难解决问题。在这种情况下,这可能是一个尝试练习的相当无趣的例子。考虑尝试像Conway's Game of Life 这样的驱动器作为一个有趣但更简单的问题。

希望有帮助!

布兰登

【讨论】:

  • 由于在这种情况下 feedparser 几乎处理了所有事情,因此可能会因为将任务委托给其他库而变得困难。在这种情况下,我觉得您的回答最能引起我的共鸣,因此我会将您的回答标记为已接受。我会尝试另一个问题而不是这个问题。
  • 这也是我学习 TDD 的经验。我从测试最终想要的行为的测试开始。然后意识到在所有小助手类和函数到位之前,测试永远不会通过。因此,在我看来,先设计,然后对每个“模块”进行 TDD 似乎是最好的方法。
【解决方案2】:

我认为您需要查看nosemock

nose 是一个很好的测试模块,它很好地补充了unittest,并提供了一个 CLI 命令来运行测试并使用插件为您提供有关测试平台结果的更多信息(代码覆盖率等)

mock 是我们存根或模拟方法或对象的方式,这对于 HTTP 请求或与测试范围之外的服务交互的对象特别有用。

在您的示例中,我将对您的 feeder 对象进行一些修补,并将返回值设置为您的一些边缘情况并进行测试以确保它正确处理self.assertTrueself.assertIsInstance(继承自unittest.TestCase)的情况) 等等...

通常在使用noseunittest 在python 中进行TDD 时,我首先使用setUp 编写TestCase 的骨架,有时使用tearDown 来处理常见的模拟和存根。对于我定义的每个测试方法,我首先模拟我必须做的,围绕单元测试设置环境,然后调用方法/对象并做出断言。

在传统的 TDD 中,您首先设计测试,然后构建代码以使您的测试绿色化。红色->绿色。

【讨论】:

    【解决方案3】:

    只要你的测试标题中有“和”,你就是在测试两件事。一次测试一件事要好得多,因此我建议您将测试重构为两件事。

    其次,您希望以非常非常小的步骤进行。想想你接下来可以做的最小的事情,这不适用于当前的代码库。

    当您没有代码时,通常最小的可能是创建目标类的示例。不要要求它做任何事情,只需创建它。

    这几乎就是你所处的情况。所以你做对了!

    您的代码不应编译,因为没有 TvSchedule。 “不编译”算作红色。写一些代码让它编译,那就是Green。耶!

    正如其他人所指出的,您应该在某处保留一个小 TODO 列表。在肯特贝克的书中,他使用便签。我喜欢在测试代码文件中有 TODO 列表。你的待办事项列表的范围应该是你打算在你将要花费的时间内完成的事情,例如半小时或两个小时或其他什么。不是一整天,只是从现在到下一次休息。然后你在你的 TODO 列表中添加和减去一些东西。帮助您专注于做“可能出错的最简单的事情”。

    [编辑:添加 TODO 列表]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-14
      • 2011-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多