测试需要使用 Factory Boy 进行用户身份验证的 Django 视图
Testing Django view requiring user authentication with Factory Boy
我需要一个允许员工用户查看处于草稿状态的对象的视图。但是我发现很难为此视图编写单元测试。
我正在使用 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)
除了使用客户端之外的另一种方法,我发现实例化视图并直接将请求传递给它很有帮助。
self.request.user = UserFactory()
view = ReleaseView.as_view()
response = view(self.request)
然后你就可以
self.assertEqual(response.status_code, desired_status_code)
如果您愿意,甚至可以呈现响应。
实际上,您收到 404
错误,因为 self.client.login
调用失败。
当您传递 password=self.user.password
时,您发送的是密码的哈希值,而不是密码本身。
当您调用UserFactory()
时,factory_boy在您工厂采取的步骤是:
- 使用
{'username': "<random>", 'is_active': True, 'is_staff': True, 'email': "<fuzzed>@email.com"}
创建一个对象
save()
它
- 致电
user.set_password('my_secret')
- 再次呼叫
user.save()
到那时,user.password
是set_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
class 已声明。
您应该改用 factory.fuzzy.FuzzyText(chars='abcdefghijklmnopqrstuvwxyz', length=12, suffix='@example.com')
.
我需要一个允许员工用户查看处于草稿状态的对象的视图。但是我发现很难为此视图编写单元测试。
我正在使用 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)
除了使用客户端之外的另一种方法,我发现实例化视图并直接将请求传递给它很有帮助。
self.request.user = UserFactory()
view = ReleaseView.as_view()
response = view(self.request)
然后你就可以
self.assertEqual(response.status_code, desired_status_code)
如果您愿意,甚至可以呈现响应。
实际上,您收到 404
错误,因为 self.client.login
调用失败。
当您传递 password=self.user.password
时,您发送的是密码的哈希值,而不是密码本身。
当您调用UserFactory()
时,factory_boy在您工厂采取的步骤是:
- 使用
{'username': "<random>", 'is_active': True, 'is_staff': True, 'email': "<fuzzed>@email.com"}
创建一个对象
save()
它- 致电
user.set_password('my_secret')
- 再次呼叫
user.save()
到那时,user.password
是set_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
class 已声明。
您应该改用 factory.fuzzy.FuzzyText(chars='abcdefghijklmnopqrstuvwxyz', length=12, suffix='@example.com')
.