代码之家  ›  专栏  ›  技术社区  ›  Konstantin Spirin

在python中TDD是否中断?

  •  3
  • Konstantin Spirin  · 技术社区  · 16 年前

    假设我们有班 UserService 带属性 current_user . 假设它用于 AppService 班级。

    我们有 附加服务 包括测试。在测试设置中,我们中断了 当前用户 具有一些模拟值:

    UserService.current_user = 'TestUser'
    

    假设我们决定重命名 当前用户 active_user . 我们把它重命名为 用户服务 但是忘记改变它在 附加服务 .

    我们进行测试,他们通过了!测试设置添加属性 当前用户 仍然(错误但成功地)用于 附加服务 .

    现在我们的测试没用了。它们通过了,但应用程序将在生产中失败。

    我们不能依赖我们的测试套件==gt;TDD是不可能的。

    在python中TDD是否中断?

    3 回复  |  直到 15 年前
        1
  •  2
  •   Gabriel Ščerbák    16 年前

    问题不在TDD中,也不在Python中。首先,TDD并不能证明当所有测试都通过时,您的应用程序是好的。想象一下,例如multiplyby2()函数,它可以通过输入1、2、3和输出2、4、8进行测试,现在想象一下,您实现了multiplyby2作为平方。所有测试都通过了,代码覆盖率为100%,并且实现错误。你必须明白,TDD只能给你保证,一旦你的测试失败,你的应用程序就出了问题,没有什么比这更糟了。因此,正如其他答案中所建议的,问题在于您没有失败的测试。如果您使用了一些静态类型的语言,编译器会为您做这个测试,并抱怨使用了不存在的方法。这并不意味着您应该使用静态类型语言,它只是意味着您需要用动态类型语言编写更多的测试。 如果您对实现代码的正确性感兴趣,那么您应该查看契约式设计,以确保至少在运行时和正式规范期间的正确性,从而至少为某些算法提供证明,但我想这与标准编码相差甚远。

        2
  •  1
  •   Konstantin Spirin    15 年前

    好的,我找到了解决办法。蟒蛇图书馆 Mock does what I want .

    下面是我最后得到的代码。

    模型和服务定义:

    class User(object):
        def __init__(self):
            self.roles = []
    
    
    class UserService(object):
        def get_current_user(self):
            return None # get from environment, database, etc.
    
        current_user = property(get_current_user)
    
    
    class AppService(object):
        def __init__(self, userService):
            self.userService = userService
    
        def can_write(self):
            return 'admin' in self.userService.current_user.roles
    

    以下是如何测试 can_write 方法 AppService 对于不同的用户:

    class AppServiceTests(unittest.TestCase):
        def test_can_write(self):
            user = User()
    
            @patch_object(UserService, 'current_user', user)
            def can_write():
                appService = AppService(UserService())
                return appService.can_write()
    
            user.roles = ['admin']
            self.assertTrue(can_write())
    
            user.roles = ['user']
            self.assertFalse(can_write())
    

    如果重命名属性 current_user 只在课堂上 UserService ,尝试修补对象时会出错。这是我一直在寻找的行为。

        3
  •  0
  •   Carl Manaster    16 年前

    在更改之前,根据当前用户的值,对象的行为应该有所不同。我们称之为谓词()。请原谅我的python;考虑一下这个伪代码:

    UserService.current_user = 'X'
    assertFalse(obj.predicate())
    UserService.current_user = 'Y'
    assertTrue(obj.predicate())
    

    好啊?所以,这是你的测试。让它过去。现在更改测试中的类,以便将当前用户重命名为活动用户。现在,无论是在第一个断言时,还是在第二个断言时,测试都将失败。因为您不再更改以前称为当前用户的字段的值,所以谓词在这两种情况下都将为假或真。现在您有了一个非常集中的测试,当类发生变化时,它会提醒您,从而使另一个测试的设置失效。