首页 > 解决方案 > 如何在 Django 管理页面的单元测试中对用户进行身份验证?

问题描述

我正在尝试调整来自Testing custom admin actions in django的答案,但我遇到了一些意外行为。我创建了一个简化的 Django 应用程序myapp,它有一个WorkerInvoice模型:

class Worker(models.Model):
    name = models.CharField(max_length=255)


class Invoice(models.Model):
    UNPAID = 0
    PAID = 1

    worker = models.ForeignKey(
        'Worker', on_delete=models.CASCADE)
    amount = models.DecimalField(
        max_digits=10, decimal_places=2)
    amount_paid = models.DecimalField(
        max_digits=10, decimal_places=2, default=Decimal('0.00'))
    status = models.IntegerField(
        choices=[(UNPAID, 'Unpaid'), (PAID, 'Paid')], default=0)

我创建了一个名为的自定义管理操作mark_as_paid,它将所选发票的状态更改为Invoice.PAIDin admin.py

from django.contrib import admin
from django.db.models import F

from .models import Invoice


@admin.register(Invoice)
class InvoiceAdmin(admin.ModelAdmin):
    list_display = ('worker', 'status', 'amount', 'amount_paid')
    actions = ['mark_as_paid']

    def mark_as_paid(self, request, queryset):
        queryset.update(amount_paid=F('amount'))

我正在尝试这样测试:

from decimal import Decimal

from django.contrib import admin
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse

from myapp.models import Invoice, Worker


class InvoiceAdminTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username='foobar',
            email='foo@bar.com',
            password='barbaz',
            is_superuser=True)
        self.client.force_login(user=self.user)

    def test_mark_as_paid(self):
        worker = Worker.objects.create(name="John Doe")
        invoice = Invoice.objects.create(
            worker=worker, amount=Decimal('100.00'))

        response = self.client.post(
            reverse('admin:myapp_invoice_changelist'),
            data={
                'action': 'mark_as_paid',
                admin.ACTION_CHECKBOX_NAME: [invoice.id]})

        import ipdb; ipdb.set_trace()

        invoice.refresh_from_db()
        self.assertEqual(invoice.amount_paid, Decimal('100.00'))

我在测试中设置了调试器跟踪,但最终我希望它通过。但是,目前它正在失败,因为invoice.amount_paid仍然是Decimal('0.00').

奇怪的是,响应的状态码为 302(不是 200)和空内容:

ipdb> response.status_code                                                               
302
ipdb> response.content                                                                   
b''

我还在该mark_as_paid()方法中设置了一个跟踪并且它没有被命中,所以我怀疑我模拟用户身份验证的方式有问题,因为如果我创建一个超级用户python manage.py createsuperuser并手动测试它,一切正常正如预期的那样。

知道这种方法有什么问题吗?

标签: pythondjango

解决方案


更仔细地查看在 django中测试自定义管理操作的示例,结果发现我需要使用该create_superuser()方法而不是create_user()with is_superuser=True。测试通过以下修改setUp()方法:

class InvoiceAdminTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_superuser(
            username='foobar',
            email='foo@bar.com',
            password='barbaz')
        self.client.force_login(user=self.user)

推荐阅读