【问题标题】:how to write django test meant to fail?如何编写意味着失败的django测试?
【发布时间】:2011-05-12 05:10:29
【问题描述】:

我有一个名为 Thing 的模型,其属性名为 name,我希望 name 是一个 只有 3 个字符长的字符字段。

如何为此编写测试?

class TestCase1(TestCase):
    def test1(self):
        thing = Thing(name='1234')

该测试应该失败。如何正确编写测试,以便在该对象失败时测试通过?

【问题讨论】:

    标签: django testing tdd


    【解决方案1】:

    这样的事情应该可以工作:

    thing = Thing.objects.create(name='1234')  
    # not sure if you need here .get() or if. create() truncates the field on its own
    self.assertEqual(thing.name, '123') # or: self.assertEqual(len(thing.name), 3)
    

    -- 但这样的测试看起来很奇怪 :-)

    另外,请注意 MySQLdb 后端会引发警告异常以通知您截断字符串,因此您可能需要使用assertRaises 进行检查。

    【讨论】:

      【解决方案2】:

      如果您希望 Thing(name='1234') 引发异常,有两种方法可以解决此问题。

      一种是使用Django的assertRaises(实际上来自unittest/unittest2):

      def mytest(self):
          self.assertRaises(FooException, Thing, name='1234')
      

      除非 Thing(name='1234') 引发 FooException 错误,否则此操作将失败。另一种方法是捕获预期的异常并在没有发生时引发异常,如下所示:

      def mytest(self):
          try:
              thing = Thing(name='1234')
              self.fail("your message here")
          except FooException:
              pass
      

      显然,将 FooException 替换为您希望从创建带有太长字符串的对象中得到的那个。验证错误?

      第三种选择(从 Python 2.7 开始)是使用 assertRaises 作为上下文管理器,这使得代码更清晰、更易读:

      def mytest(self):
          with self.assertRaises(FooException):
              thing = Thing(name='1234')
      

      遗憾的是,这不允许自定义测试失败消息,因此请妥善记录您的测试。详情请见https://hg.python.org/cpython/file/2.7/Lib/unittest/case.py#l97。

      【讨论】:

      • 我经常使用 assertRaises。
      • 我也这样做,但语法需要一些时间来适应。
      • 在python 2.6.5版本中,函数签名不同。从 python 代码复制:def failUnlessRaises(self, excClass, callableObj, *args, **kwargs),然后是callableObj(*args, **kwargs)。所以在这篇文章的例子中,它将是self.assertRaises(FooException, Thing, name='1234')。我不确定为什么我的函数签名不同,但这就是有效的。
      • 其实我觉得这种情况已经有一段时间了。我只是把信号倒过来了。我会更新我的答案。
      • assertRaises 也可以用在这样的 with 语句中:with self.assertRaises(FooException): thing = Thing(name='1234')
      【解决方案3】:

      我目前正在使用来自unittest 的expectedFailure 装饰器。就像宣传的那样工作:没有错误时失败,失败时通过。

      我使用expectedFailure 来验证我的自定义断言例程是否确实有效,而不仅仅是橡皮戳一切正常。

      import unittest
      from django.test import TestCase
      
      class EmojiTestCase(TestCase):
      
          @unittest.expectedFailure
          def testCustomAssert(self):
              self.assertHappyFace(':(') # must fail.
      

      但在测试期间会打印一条警告消息。我将它与 Django 和鼻子一起使用。 others 也见过。

      /usr/lib64/python3.4/unittest/case.py:525:RuntimeWarning:TestResult 没有 addExpectedFailure 方法,报告为通过 运行时警告)

      我来这里是为了寻找更好的解决方案,但没有找到。所以我至少想告诉其他人我一直在做的事情。

      【讨论】:

        【解决方案4】:

        在我之前的项目中,我不得不做一些测试驱动开发之类的事情,所以我编写了一些必须捕获某些类型错误的测试用例。如果它没有得到错误,那么我搞砸了。在这里分享我的代码。

        from django.test import TestCase
        from django.contrib.auth.models import User
        
        class ModelTest(TestCase):
        
        def test_create_user_with_email(self):
        
            with self.assertRaises(TypeError):
                email = "ah@gmail.com"
                password = 'testpass1'
        
                user = User.objects.create_user(
                    email = email,
                    password = password,)
        
                self.assertEqual(user.email, email)
                self.assertTrue(user.check_password(password))
        

        您可以看到我尝试使用电子邮件和密码创建用户,但默认 Django 用户模型需要“用户名”和“密码”参数来创建用户。所以在这里我的测试用例必须引发“TypeError”。这就是我在这里尝试做的。

        【讨论】:

          猜你喜欢
          • 2018-07-12
          • 2022-11-04
          • 2011-06-04
          • 1970-01-01
          • 2011-02-16
          • 2013-12-05
          • 2012-11-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多