【发布时间】:2010-09-11 06:09:03
【问题描述】:
我想确保我是单独测试模型/对象,而不是作为一个庞大的系统。
如果我有一个 Order 对象,并且它具有客户、付款、OrderItems 等的外键,并且我想测试 Order 功能,我需要为所有相关数据创建固定装置,或者在代码中创建它。我认为我真正需要做的是模拟其他项目,但如果我对这些外键进行查询,我看不到一个简单(或可能)的解决方案。
常见的解决方案(夹具)并不能真正让我一次测试一个对象。我确信这部分是由于我的应用方式过度耦合造成的。
我正在尽最大努力采用 TDD 作为我的主要工作方法,但使用 Django 的工作方式,您似乎可以运行非常琐碎的单元测试,或者这些大规模的集成测试。
[编辑]更好的明确示例和更谦逊的态度
我的意思是 我似乎 只能运行微不足道的单元测试。我见过人们使用经过良好测试和细化的模块。我确信其中一些可以追溯到糟糕的设计。
例子:
我有一个名为 Upsell 的模型,它链接到 Product 模型。然后我有一个 Choices 模型,它是 Upsell 的子代(你想要 #1、#2、#3 门后面的东西吗)。
Upsell 模型上有几种方法,可以从他们的选择中派生呈现模板所需的项目。最重要的是它为每个选择创建一个 URL。它通过一些字符串修饰等来做到这一点。如果我想测试 Upsell.get_urls() 方法,我希望它不依赖于固定装置中选择的值,并且我不希望它依赖于灯具中的产品。
现在我在 setUp 方法中为测试填充数据库,这与 Django 每次都退出事务的方式很好,但仅限于 setUp 和 tearDown 之外。这工作得很好,除了一些模型设置起来相当复杂,而我实际上只需要为它获取一个属性。
我不能给你一个例子,因为我无法完成它,但这是我现在正在做的事情的类型。基本上我输入了一个完整的订单,创建了它所附加的 A/B 实验,等等。这还不包括由夹具设置的产品、类别等。这不是我关心的额外工作,因为我什至不能一次测试一个基于数据库的对象。下面的测试很重要,但它们是集成测试。我想通过分别测试每个项目来建立这样的东西。正如您所指出的,也许我不应该选择与数据库紧密相关的框架。像这样的东西是否存在任何类型的依赖注入? (超出我的测试范围,但代码本身也是如此)
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 框架。所以我也可能只是从根本上错过了一些东西。
【问题讨论】:
标签: django unit-testing django-models mocking