简体   繁体   English

使用Factory Boy测试需要用户身份验证的Django视图

[英]Testing Django view requiring user authentication with Factory Boy

I need a view that allows staff users to view objects in a draft state. 我需要一个允许工作人员用户查看处于草稿状态的对象的视图。 But I'm finding it difficult to write a unittest for this view. 但是我发现很难为此视图编写单元测试。

I'm using Factory Boy for my setup: 我正在使用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)

Given that I now have a logged-in, staff user for my tests, how do I go about using that to test against for a view (status_code 200 instead of 404)? 鉴于我现在有一个登录的工作人员用户来进行测试,我该如何使用该用户来测试视图(status_code 200而不是404)?

For instance, this test fails (404 != 200) when my view allows for users with is_staff as True to access the view: 例如,当我的视图允许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)

Actually, you receive a 404 error because the self.client.login call fails. 实际上,由于self.client.login调用失败,您会收到404错误。

When you're passing password=self.user.password , you're sending the hash of the password, not the password itself. 当传递password=self.user.password ,您发送的是密码的哈希值,而不是密码本身。

When you call UserFactory() , the steps taken by factory_boy in your factory are: 调用UserFactory()UserFactory()在工厂中采取的步骤是:

  1. Create an object with {'username': "<random>", 'is_active': True, 'is_staff': True, 'email': "<fuzzed>@email.com"} 创建一个对象,其对象为{'username': "<random>", 'is_active': True, 'is_staff': True, 'email': "<fuzzed>@email.com"}
  2. save() it save()
  3. Call user.set_password('my_secret') 呼叫user.set_password('my_secret')
  4. Call user.save() again 再次调用user.save()

By then, user.password is the result of set_password('my_secret') , not 'my_secret' . 届时, user.password是的结果 set_password('my_secret')而不是'my_secret'

I'd go for (in your test): 我会去(在您的测试中):

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

By the way, the declaration of your email field won't work as you expect it: when you write factory.fuzzy.FuzzyText(...).fuzz().lower() , this gets executed only once , when the UserFactory class is declared. 顺便说一句,您的电子邮件字段的声明将无法按您预期的方式工作:当您编写factory.fuzzy.FuzzyText(...).fuzz().lower()UserFactory时执行一次类被声明。

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

An alternative way than using the client, I have found it is helpful to instantiate the view and directly pass it the request. 除了使用客户端以外,我还发现了一种实例化视图并将其直接传递给请求的方法很有帮助。

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

And then you can 然后你可以

self.assertEqual(response.status_code, desired_status_code)

And even render the response if you so desire. 如果您愿意,甚至可以做出回应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM