测试Django视图需要用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)

实际上,您会收到一个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))

顺便说一下,您的电子邮件字段的声明不会按预期工作:当您编写fuzzy.FuzzyText(...).fuzz().lower()时,这只会在声明UserFactory类时执行一次

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

一种比使用客户端的另一种方式,我发现实例化视图并直接向其传递请求很有帮助。

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

然后你可以

self.assertEqual(response.status_code, desired_status_code)

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

最新更新