Django - 测试结转 POST 变量

Django - Testing Carrying Over POST Variables

当我 运行 陷入这个有趣的困境时,我正在为我的 Django 应用程序做一些代码覆盖单元测试。

tests/test_views.py

class TestLogin(TestCase):
    def setUp(self):
        self.client = Client()
        self.url = reverse('account:login')
        self.template = 'account/login.html'

    # This test works
    def test_POST_invalid_login(self):
        response = self.client.post(self.url, {
            'username': 'foo',
            'password': 'bar'
        })
        self.assertEqual(response.status_code, 401)
        self.assertTemplateUsed(response, self.template)

    # This is not working as intended.
    def test_POST_no_data(self):
        with self.assertRaises(MultiValueDictKeyError):
            self.client.post(self.url, None)

views.py

class Login(View):
    form_class = LoginForm
    template = 'account/login.html'

    def get(self, request):
        form = self.form_class(None)
        context = {
            'form': form
        }

        return render(request, self.template, context)

    def post(self, request):
        try:
            # Retrieve the username and password
            username = request.POST['username']
            password = request.POST['password']

            # Create a user object from authentication, or return None
            user = authenticate(username=username, password=password)

            # Check if user was created
            if user is not None:
                # Login the user to the website
                login(request, user)

                messages.success(request, 'Login successful! Welcome ' + user.first_name + ' ' + user.last_name)

                # Eventually have this go to profile pages.
                return redirect('home', permanent=True)
            else:
                messages.error(request, 'Login failed: Invalid User.')

        except MultiValueDictKeyError:
            messages.error(request, 'Login failed: Invalid User.')

        # Clear the form since the login attempt failed.
        form = self.form_class(None)

        context = {
            'form': form
        }

        return render(request, self.template, context, status=401)

第一个测试,test_POST_invalid_login 按预期发送数据,但第二个测试,test_POST_no_data 不应该发送任何数据,但视图仍然识别 foobar 用户名和密码值因此没有捕获异常。我最初先写了 no data 测试,它最初工作。我尝试将测试方法移至 invalid login 测试上方,但它仍然会失败。

有什么建议吗?

您的 test_POST_no_data 测试断言 MultiValueDictKeyError 已引发,但此异常已在视图中捕获,因此视图永远不会引发它。所以,test_POST_no_data 应该类似于 test_POST_invalid_login,即应该声明相同的东西。

您可以通过在 except MultiValueDictKeyError: 块中编写一个空的 raise 语句来检查这是真的。这样,您将重新引发相同的异常并且您的测试将通过。

因为我想在代码中捕获异常;我决定重构 no data 测试来检查它是否会得到以下断言。当然,我可以删除 try/except 块,并检查 request.POST 是否具有以下键:usernamepassword,但我希望它优雅地失败并让应用程序运行返回带有失败消息的登录页面,而不是通过单元测试进行轮廓化。

tests/test_view.py

# Refactored, and working
def test_POST_no_data(self):
    self.assertEqual(response.status_code, 401)
    self.assertTemplateUsed(response, self.template)

如果这是处理异常和测试异常的最佳方式,我可以提出另一个问题,但那将是另一个问题。

谢谢 Iulia Chiriac 的回答。