【问题标题】:Testing Django view requiring user authentication with Factory Boy测试需要使用 Factory Boy 进行用户身份验证的 Django 视图
【发布时间】:2015-04-18 17:43:21
【问题描述】:

我需要一个允许员工用户查看处于草稿状态的对象的视图。但是我发现很难为这个视图编写单元测试。

我正在使用 Factory Boy 进行设置:

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User

    username = factory.LazyAttribute(lambda t: random_string())
    password = factory.PostGenerationMethodCall('set_password', 'mysecret')
    email = fuzzy.FuzzyText(
        length=12, suffix='@email.com').fuzz().lower()
    is_staff = True
    is_active = True

class ReleaseFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Release

    headline = factory.LazyAttribute(lambda t: random_string())
    slug = factory.LazyAttribute(lambda t: slugify(t.headline))
    author = factory.LazyAttribute(lambda t: random_string())
    excerpt = factory.LazyAttribute(lambda t: random_string())
    body = factory.LazyAttribute(lambda t: random_string())

class TestReleaseViews(TestCase):
    """
    Ensure our view returns a list of :model:`news.Release` objects.
    """

    def setUp(self):
        self.client = Client()
        self.user = UserFactory.create()
        self.client.login(username=self.user.username, password=self.user.password)

鉴于我现在有一个已登录的员工用户进行测试,我该如何使用它来测试视图(status_code 200 而不是 404)?

例如,当我的视图允许 is_staff 为 True 的用户访问视图时,此测试失败 (404 != 200):

def test_staff_can_view_draft_releases(self):
    "ReleaseDetail view should return correct status code"
    release = ReleaseFactory.create(status='draft')
    response = self.client.get(
        reverse(
            'news:release_detail',
            kwargs={
                'year': release.created.strftime('%Y'),
                'month': release.created.strftime('%b').lower(),
                'day': release.created.strftime('%d'),
                'slug': release.slug
            }
        )
    )
    self.assertEqual(response.status_code, 200)

【问题讨论】:

    标签: django django-unittest factory-boy


    【解决方案1】:

    实际上,您收到404 错误是因为self.client.login 调用失败。

    当您传递 password=self.user.password 时,您发送的是密码的哈希值,而不是密码本身。

    当您拨打UserFactory()时,您工厂的factory_boy采取的步骤是:

    1. 使用{'username': "<random>", 'is_active': True, 'is_staff': True, 'email': "<fuzzed>@email.com"} 创建一个对象
    2. save()
    3. 致电user.set_password('my_secret')
    4. 再次致电user.save()

    到那时,user.passwordset_password('my_secret')结果,而不是'my_secret'

    我会选择(在你的测试中):

    pwd = 'my_super_secret'
    self.user = UserFactory(password=pwd)
    self.client = Client()
    self.assertTrue(self.client.login(username=self.user.username, password=pwd))
    

    顺便说一句,你的电子邮件字段的声明不会像你期望的那样工作:当你写 factory.fuzzy.FuzzyText(...).fuzz().lower() 时,这会被执行一次,当 UserFactory 类被声明时.

    您应该改用factory.fuzzy.FuzzyText(chars='abcdefghijklmnopqrstuvwxyz', length=12, suffix='@example.com')

    【讨论】:

      【解决方案2】:

      除了使用客户端之外,我发现实例化视图并直接将请求传递给它很有帮助。

      self.request.user = UserFactory()
      view = ReleaseView.as_view()
      response = view(self.request)
      

      然后你就可以了

      self.assertEqual(response.status_code, desired_status_code)
      

      如果您愿意,甚至可以呈现响应。

      【讨论】:

      • 谢谢!如果我继续沿着这条路线走,我将如何使用客户端?
      • 我会做一些调试 - 如果用户不是员工而不是 404,您是否打算返回 403?我会检查视图为什么会失败并将其记录到标准输出。否则,看起来您已经为工厂男孩正确设置了它。 PostGeneration 是否正确设置了密码的值?如果你直接传入密码而不是user.password,会发生什么?
      猜你喜欢
      • 1970-01-01
      • 2015-05-02
      • 2013-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-10
      • 2017-10-25
      相关资源
      最近更新 更多