Как протестировать модели в Django с иностранными ключами - PullRequest
9 голосов
/ 11 сентября 2010

Я хочу убедиться, что я тестирую Модели / Объекты изолированно, а не как одну огромную систему.

Если у меня есть объект Order и у него есть внешние ключи для клиентов, Payments, OrderItems и т. Д., И я хочу проверить функциональность Order, мне нужно создать осветительные приборы для всех этих связанных данных или создать их в коде. Я думаю, что мне действительно нужно делать макет других элементов, но я не вижу простого (или возможного) решения для этого, если я выполняю запросы к этим внешним ключам.

Обычные решения (приборы) не позволяют мне тестировать один Объект за раз. Я уверен, что это отчасти связано с тем, что мое приложение way over overbired.

Я стараюсь изо всех сил принять TDD в качестве основного метода работы, но, как работает Django, кажется, что вы можете запустить либо очень тривиальные модульные тесты, либо эти масштабные интеграционные тесты.

[Редактировать] Более точный пример и немного скромнее

Я имею в виду, что Кажется, может выполнять только тривиальные юнит-тесты. Я видел людей с очень хорошо проверенными и детальными модулями. Я уверен, что отчасти это может последовать за плохим дизайном.

Пример:

У меня есть вызов модели Upsell, который связан с моделью продукта. Тогда у меня есть модель Choices, которые являются детьми Upsell (хотите, что находится за дверью № 1, № 2, № 3).

Модель Upsell имеет несколько методов, которые извлекают элементы, необходимые для визуализации шаблона по их выбору. Наиболее важным является то, что он создает URL для каждого варианта. Он делает это посредством некоторого искажения строк и т. Д. Если я хотел протестировать метод Upsell.get_urls (), я бы хотел, чтобы он не зависел от значений выбора в приборах, и я хочу, чтобы он не зависел от значения Товар в светильниках.

Прямо сейчас я заполняю базу данных в методе setUp для тестов, и это хорошо работает с тем, как Django каждый раз отклоняет транзакцию, но только за пределами setUp и tearDown. Это работает довольно хорошо, за исключением того, что некоторые модели довольно сложны в настройке, хотя мне нужно только получить один атрибут для этого.

Я не могу привести вам пример этого, поскольку я не могу этого сделать, но вот что я сейчас делаю. По сути, я ввожу весь заказ, создаю эксперимент A / B, к которому он был прикреплен и т. Д. И это не считая Product, Categories и т. Д., Все настроенные осветителями. Это не лишняя работа, я обеспокоен тем, что не могу даже протестировать один объект на основе базы данных одновременно. Приведенные ниже тесты важны, но они являются интеграционными тестами. Я хотел бы создать нечто подобное, протестировав каждый элемент отдельно. Как вы указали, возможно, мне не следовало выбирать рамки, так тесно связанные с БД. Существует ли какая-либо инъекция зависимости с чем-то вроде этого? (вне моего тестирования, но и сам код)

class TestMultiSinglePaySwap(TestCase):
    fixtures = ['/srv/asm/fixtures/alchemysites.json','/srv/asm/fixtures/catalog.json','/srv/asm/fixtures/checkout_smallset.json','/srv/asm/fixtures/order-test-fixture.json','/srv/asm/fixtures/offers.json']

def setUp(self):
    self.o = Order()
    self.sp = SiteProfile.objects.get(pk=1)
    self.c = Customer.objects.get(pk=1)
    signals.post_save.disconnect(order_email_first, sender=Order)
    self.o.customer = self.c
    p = Payment()
    p.cc_number = '4444000011110000'
    p.cc_exp_month = '12'
    p.cc_type = 'V'
    p.cc_exp_year = '2020'
    p.cvv2 = '123'
    p.save()
    self.o.payment = p
    self.o.site_profile = self.sp
    self.o.save()
    self.initial_items = []
    self.main_kit = Product.objects.get(pk='MOA1000D6')
    self.initial_items.append(self.main_kit)
    self.o.add_item('MOA1000D6', 1, False)
    self.item1 = Product.objects.get(pk='MOA1041A-6')
    self.initial_items.append(self.item1)
    self.o.add_item('MOA1041A-6', 1, False)
    self.item2 = Product.objects.get(pk='MOA1015-6B')
    self.initial_items.append(self.item2)
    self.o.add_item('MOA1015-6B', 1, False)
    self.item3 = Product.objects.get(pk='STP1001-6E')
    self.initial_items.append(self.item3)
    self.o.add_item('STP1001-6E', 1, False)
    self.swap_item1 = Product.objects.get(pk='MOA1041A-1')

def test_single_pay_swap_wholeorder(self):
    o = self.o
    swap_all_skus(o)
    post_swap_order = Order.objects.get(pk = o.id)
    swapped_skus = ['MOA1000D','MOA1041A-1','MOA1015-1B','STP1001-1E']
    order_items = post_swap_order.get_all_line_items()
    self.assertEqual(order_items.count(), 4)
    pr1 = Product()
    pr1.sku = 'MOA1000D'
    item = OrderItem.objects.get(order = o, sku = 'MOA1000D') 
    self.assertTrue(item.sku.sku == 'MOA1000D')
    pr2 = Product()
    pr2.sku = 'MOA1015-1B'
    item = OrderItem.objects.get(order = o, sku = 'MOA1015-1B') 
    self.assertTrue(item.sku.sku == 'MOA1015-1B')
    pr1 = Product()
    pr1.sku = 'MOA1041A-1'
    item = OrderItem.objects.get(order = o, sku = 'MOA1041A-1') 
    self.assertTrue(item.sku.sku == 'MOA1041A-1')
    pr1 = Product()
    pr1.sku = 'STP1001-1E'
    item = OrderItem.objects.get(order = o, sku = 'STP1001-1E') 
    self.assertTrue(item.sku.sku == 'STP1001-1E')

Обратите внимание, что я никогда не использовал Mock Framework, хотя я пробовал. Так что я могу здесь просто что-то упустить.

Ответы [ 2 ]

4 голосов
/ 24 октября 2013

Посмотрите на модель мамочки .Он может автоматически создавать объекты с помощью внешних ключей.

4 голосов
/ 11 сентября 2010

Это, вероятно, не ответит на ваш вопрос, но может дать пищу для размышлений.

По моему мнению, когда вы тестируете проект или приложение, поддерживаемое базой данных, существует предел того, что вы можете высмеивать.Это особенно верно, когда вы используете фреймворк и ORM, такие как тот, который предлагает Django.В Django нет различия между классом бизнес-модели и классом персистентной модели.Если вы хотите такого различия, вам придется добавить его самостоятельно.

Если вы сами не захотите добавить этот дополнительный уровень сложности, то будет сложно протестировать бизнес-объекты в одиночку, не прибегая к осветительным приборам и т. Д. Если вы должны это сделать, вам придется взяться за некоторые из магических действий.сделано Django.

Если вы решите стиснуть зубы и закопаться, тогда Python Майкла Фоорда Библиотека Mock пригодится вам.

ЯЯ стараюсь изо всех сил принять TDD в качестве основного метода работы, но, как все работает с Django, кажется, что вы можете запустить либо очень тривиальные модульные тесты, либо эти массивные интеграционные тесты.

Я использовалМеханизм модульного тестирования Django для написания нетривиальных модульных тестов.Мои требования, несомненно, сильно отличались от ваших.Если вы сможете предоставить более подробную информацию о том, что вы пытаетесь достичь, тогда пользователи здесь смогут предложить другие альтернативы.

...