Проблема с тестированием пользовательских действий администратора
Столкнулся с некоторыми проблемами при тестировании моих пользовательских действий администратора.
Сначала я могу показать вам пример теста, который работает, и действия, которые он проверяет.
пользовательское действие, модель продукта
@admin.action(description="Merge selected products")
def merge_products(self, request, queryset):
list_of_products = queryset.order_by("created_at")
list_of_products = list(list_of_products)
canonical_product = list_of_products[0]
list_of_products.remove(canonical_product)
for p in list_of_products:
for ep in p.external_products.all():
ep.internal_product = canonical_product
ep.save()
p.save()
canonical_product.save()
связанный тест
class MockRequest(object):
pass
class ProductAdminTest(TestCase):
def setUp(self):
self.product_admin = ProductAdmin(model=Product, admin_site=AdminSite())
User = get_user_model()
admin_user = User.objects.create_superuser(
username="superadmin", email="superadmin@email.com", password="testpass123"
)
self.client.force_login(admin_user)
def test_product_merge(self):
self.boot1 = baker.make("products.Product", title="Filippa K boots", id=uuid4())
self.boot2 = baker.make("products.Product", title="Filippa K boots", id=uuid4())
self.external_product1 = baker.make(
"external_products.ExternalProduct", internal_product=self.boot1
)
self.external_product2 = baker.make(
"external_products.ExternalProduct", internal_product=self.boot2
)
self.assertEqual(self.boot1.external_products.count(), 1)
self.assertEqual(self.boot2.external_products.count(), 1)
request = MockRequest()
queryset = Product.objects.filter(title="Filippa K boots")
self.product_admin.merge_products(request, queryset)
self.assertEqual(self.boot1.external_products.count(), 2)
self.assertEqual(self.boot2.external_products.count(), 0)
Возможно, это не самый красивый тест, но он работает, как и действие.
Приведенный выше код работает как надо, но при попытке протестировать почти идентичное действие, но для другой модели, возникли проблемы.
заказное действие, Брендовая модель
@admin.action(description="Merge selected brands")
def merge_brands(self, request, queryset):
qs_of_brands = queryset.order_by("created_at")
list_of_brands = list(qs_of_brands)
canonical_brand = list_of_brands[0]
for brand in list_of_brands:
if brand.canonical:
canonical_brand = brand
list_of_brands.remove(canonical_brand)
for brand in list_of_brands:
brand.canonical_brand = canonical_brand
brand.save()
for product in Product.objects.filter(brand=brand):
product.brand = canonical_brand
product.save()
canonical_brand.save()
связанный тест
class MockRequest(object):
pass
def setUp(self):
self.brand_admin = BrandAdmin(model=Brand, admin_site=AdminSite())
User = get_user_model()
admin_user = User.objects.create_superuser(
username="superadmin", email="superadmin@email.com", password="testpass123"
)
self.client.force_login(admin_user)
def test_brand_merge(self):
self.brand1 = baker.make("brands.Brand", title="Vans")
self.brand1.canonical_brand = self.brand1
self.brand1.active = True
self.brand1.save()
self.brand2 = baker.make("brands.Brand", title="Colmar")
self.boot1 = baker.make("products.Product", brand=self.brand1, id=uuid4())
self.boot2 = baker.make("products.Product", brand=self.brand2, id=uuid4())
self.assertEqual(self.boot1.brand, self.brand1)
self.assertEqual(self.boot2.brand, self.brand2)
self.assertEqual(self.brand1.active, True)
self.assertEqual(self.brand2.active, False)
request = MockRequest()
queryset = Brand.objects.all()
self.brand_admin.merge_brands(request, queryset)
self.assertEqual(self.boot1.brand, self.brand1)
self.assertEqual(self.boot2.brand, self.brand1)
self.assertEqual(self.brand1.active, True)
self.assertEqual(self.brand2.active, False)
self.assertEqual(self.brand1.canonical_brand, self.brand1)
self.assertEqual(self.brand2.canonical_brand, self.brand1)
На самом деле не обязательно, как работает код выше, но я включил его для контекста.
Действие администрирования продукта работает как при ручной проверке, так и в тестовом пакете. Действие бренда работает как положено при проверке вручную, но в тестовом пакете оно ничего не делает
self.brand_admin.merge_brands(request, queryset)
никак не изменяет тестируемые объекты.
У меня есть еще одно пользовательское действие администратора для модели Brand, и там та же проблема, работает как шарм, когда я пробую вручную, но ничего не делает в тестовом наборе. Из-за этих фактов я предполагаю, что проблема связана с моей настройкой администратора в тестовом наборе, но она идентична настройке администратора, используемой для первого теста, который работает.
Есть идеи?
При необходимости предоставьте больше контекста.
Похоже, что вам нужно обновить объекты из базы данных, в вашем тесте self.brand1, boot1 и т.д. находятся в памяти и не будут автоматически обновляться из базы данных, вам нужно получить новые значения из базы данных
https://docs.djangoproject.com/en/4.0/ref/models/instances/#refreshing-objects-from-database
Если вам нужно перезагрузить значения модели из базы данных, вы можете использовать метод refresh_from_db(). Когда этот метод вызывается без аргументов, происходит следующее:
Все не отложенные поля модели обновляются до значений, имеющихся в базе данных. Все кэшированные отношения очищаются из перезагруженного экземпляра.
После вызова merge_brands необходимо обновить каждый объект.
self.boot1.refresh_from_db()
self.boot2.refresh_from_db()
# etc..