You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django购物车视图测试报错求助:JSON响应及断言失败

Django购物车视图测试问题排查

我正在开发一款Django应用并同步开展测试工作,以下是相关代码及遇到的错误:

视图代码(views.py)

from django.http import JsonResponse, HttpResponseBadRequest
from store.models import Product
from .basket import Basket

# Create your views here.
def basket_summary(request):
    basket = Basket(request)
    return render(request, "store/basket/summary.html", {"basket": basket})

def basket_add(request):
    basket = Basket(request)
    if request.POST.get("action") == "post":
        product_id = int(request.POST.get("productid"))
        product_qty = int(request.POST.get("productqty"))
        product = get_object_or_404(Product, id=product_id)
        basket.add(product=product, product_qty=product_qty)

        basket_qty = basket.__len__()
        response = JsonResponse({"qty": basket_qty})
        return response

def basket_delete(request):
    basket = Basket(request)
    if request.POST.get("action") == "post":
        product_id = int(request.POST.get("productid"))
        basket.delete(product_id=product_id)

        basket_qty = basket.__len__()
        basket_total = basket.get_total_price()
        response = JsonResponse({"qty": basket_qty, "subtotal": basket_total})
        return response

def basket_update(request):
    basket = Basket(request)
    if request.POST.get("action") == "post":
        product_id = int(request.POST.get("productid"))
        product_qty = int(request.POST.get("productqty"))
        basket.update(product_id=product_id, product_qty=product_qty)

        basket_qty = basket.__len__()
        basket_total = basket.get_total_price()
        response = JsonResponse({"qty": basket_qty, "subtotal": basket_total})
        return response

URL配置(urls.py)

from .views import basket_summary, basket_add, basket_delete, basket_update

app_name = "store_basket"
urlpatterns = [
    path("", basket_summary, name="basket_summary"),
    path("add/", basket_add, name="basket_add"),
    path("delete/", basket_delete, name="basket_delete"),
    path("update/", basket_update, name="basket_update"),
]

测试代码(test_views.py)

from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from store.models import Category, Product
from json import loads

class TestBasketView(TestCase):
    def setUp(self):
        category = Category.objects.create(name="django", slug="django")
        user = User.objects.create(username="admin")
        Product.objects.create(
            title="django beginners",
            category=category,
            created_by=user,
            slug="django-beginners",
            price="20.00",
            image="django",
        )
        Product.objects.create(
            title="django intermediate",
            category=category,
            created_by=user,
            slug="django-beginners",
            price="20.00",
            image="django",
        )
        Product.objects.create(
            title="django advanced",
            category=category,
            created_by=user,
            slug="django-beginners",
            price="20.00",
            image="django",
        )
        self.client.post(
            reverse("store_basket:basket_add"),
            {"productid": 1, "productqty": 1, "action": "post"},
            xhr=True,
        )
        self.client.post(
            reverse("store_basket:basket_add"),
            {"productid": 2, "productqty": 2, "action": "post"},
            xhr=True,
        )

    def test_basket_url(self):
        """
        Test homepage response status
        """
        response = self.client.get(reverse("store_basket:basket_summary"))
        self.assertEqual(response.status_code, 200)

    def test_basket_add(self):
        """
        Test adding items to the basket
        """
        response = self.client.post(
            reverse("store_basket:basket_add"),
            {"productid": 3, "productqty": 1, "action": "post"},
            xhr=True,
        )
        self.assertEqual(response.json(), {"qty": 4})
        response = self.client.post(
            reverse("store_basket:basket_add"),
            {"productid": 2, "productqty": 1, "action": "post"},
            xhr=True,
        )
        self.assertEqual(response.json(), {"qty": 3})

    def test_basket_delete(self):
        """
        Test deleting items from the basket
        """
        response = self.client.post(
            reverse("store_basket:basket_delete"),
            {"productid": 2, "action": "post"},
            xhr=True,
        )
        self.assertEqual(response.json(), {"qty": 1, "subtotal": "20.00"})

    def test_basket_update(self):
        """
        Test updating items from the basket
        """
        response = self.client.post(
            reverse("store_basket:basket_update"),
            {"productid": 2, "productqty": 1, "action": "post"},
            xhr=True,
        )
        self.assertEqual(response.json(), {"qty": 2, "subtotal": "40.00"})

测试错误信息

======================================================================
ERROR: test_basket_add (store_basket.test.test_views.TestBasketView.test_basket_add)
Test adding items to the basket
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/bottgabriel/Desktop/Practices/py/ecommerce/store_basket/test/test_views.py", line 63, in test_basket_add
    self.assertEqual(response.json(), {"qty": 4})
                     ^^^^^^^^^^^^^^^
  File "/Users/bottgabriel/Desktop/Practices/py/ecommerce/venv/lib/python3.11/site-packages/django/test/client.py", line 823, in _parse_json
    raise ValueError(
ValueError: Content-Type header is "text/html; charset=utf-8", not "application/json"

======================================================================
FAIL: test_basket_delete (store_basket.test.test_views.TestBasketView.test_basket_delete)
Test deleting items from the basket
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/bottgabriel/Desktop/Practices/py/ecommerce/store_basket/test/test_views.py", line 80, in test_basket_delete
    self.assertEqual(response.json(), {"qty": 1, "subtotal": "20.00"})
AssertionError: {'qty': 0, 'subtotal': 0} != {'qty': 1, 'subtotal': '20.00'}
- {'qty': 0, 'subtotal': 0}
?         ^

+ {'qty': 1, 'subtotal': '20.00'}
?         ^              ++ ++++


======================================================================
FAIL: test_basket_update (store_basket.test.test_views.TestBasketView.test_basket_update)
Test updating items from the basket
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/bottgabriel/Desktop/Practices/py/ecommerce/store_basket/test/test_views.py", line 91, in test_basket_update
    self.assertEqual(response.json(), {"qty": 2, "subtotal": "40.00"})
AssertionError: {'qty': 0, 'subtotal': 0} != {'qty': 2, 'subtotal': '40.00'}
- {'qty': 0, 'subtotal': 0}
?         ^

+ {'qty': 2, 'subtotal': '40.00'}
?         ^              ++ ++++


----------------------------------------------------------------------
Ran 13 tests in 0.267s

FAILED (failures=2, errors=1, skipped=1)
Destroying test database for alias 'default'...

我已调试确认视图返回的是JSON,但测试仍无法正常运行,恳请帮助!


问题排查与解决方案

1. 修复视图缺失的导入

视图代码存在两处关键导入缺失,会导致运行时错误并返回HTML错误页面:

  • basket_summary函数使用render但未导入:添加from django.shortcuts import render
  • basket_add函数使用get_object_or_404但未导入:添加from django.shortcuts import get_object_or_404

修改后的视图头部代码:

from django.http import JsonResponse, HttpResponseBadRequest
from django.shortcuts import render, get_object_or_404
from store.models import Product
from .basket import Basket

2. 移除测试中弃用的xhr=True参数

Django测试客户端的xhr参数已被弃用,且你的视图是从request.POST获取表单数据,而非解析JSON请求。删除所有测试post请求中的xhr=True,确保请求以表单编码方式提交。

示例修改:

self.client.post(
    reverse("store_basket:basket_add"),
    {"productid": 1, "productqty": 1, "action": "post"},
)

3. 修复测试数据的重复slug问题

setUp中创建的三个Product使用了相同的slug="django-beginners",即使Django默认不强制slug唯一,也可能导致后续逻辑异常。给每个产品设置唯一slug:

Product.objects.create(
    title="django intermediate",
    category=category,
    created_by=user,
    slug="django-intermediate",
    price="20.00",
    image="django",
)
Product.objects.create(
    title="django advanced",
    category=category,
    created_by=user,
    slug="django-advanced",
    price="20.00",
    image="django",
)

4. 检查Basket类的核心方法实现

测试返回qty=0和subtotal=0说明Basket类的方法可能未正确操作会话数据:

  • 确认__len__方法是否遍历购物车所有商品,返回总数量而非商品种类数
  • 确认delete方法是否正确从会话中移除对应product_id的条目
  • 确认get_total_price方法是否返回字符串格式的金额(如"20.00")而非数字类型,与测试断言匹配

内容的提问来源于stack exchange,提问作者Cwei0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:08:10