我正在使用Django 1.8。我编写了以下代码来测试pre_save
挂钩是否正常工作,但这段代码似乎非常不优雅。这是"正确的方式"写这种单元测试?
class PreSaveTests(TestCase):
def test_pre_save_hook(self):
person = Person(name="Joe")
person.save()
person2 = Person.objects.get(pk = person.pk)
# Confirm that the pre_save hook ran.
# The hook sets person.is_cool to True.
self.assertEqual(person2.is_cool, True)
这很好用,但看起来很难看。
真正丑陋的部分是person
和person2
是同一个数据库对象。唯一的区别是从数据库中检索到person2
。
答案 0 :(得分:5)
你在考试中所做的一切都很好。不过,我认为你可以简化/改进它。
我认为你应该使用工厂(你可以使用FactoryBoy
)。这样,在模型上添加/删除必填字段时,您无需更新测试。此外,您可以从测试中删除不相关的信息。在这种情况下,人名为Joe
的事实完全无关紧要。
您可以替换:
person = Person(name="Joe")
person.save()
使用:
person = PersonFactory.create()
正如Daniel所说,你不需要重新加载Person实例。所以你不必这样做:
person2 = Person.objects.get(pk = person.pk)
最后,小提示,您可以使用assertTrue
代替assertEquals(something, True)
:
class PreSaveTests(TestCase):
def test_pre_save_hook(self):
person = PersonFactory.create()
self.assertTrue(person.is_cool)
答案 1 :(得分:4)
首先,我不确定为什么你认为丑陋:这似乎是测试这种功能的完美合理方式。
然而,你绝对可以让它变得更简单。虽然Django实例没有身份 - 也就是说,从数据库中检索的两个实例分别不会共享修改,直到它们被保存和检索 - 当预保存挂钩运行时,它会修改现有实例。实际上is_cool
将进行修改以设置person2
,因此无需检索并检查Intent intent = new Intent();
ComponentName cn = new ComponentName("com.whatsapp", "com.whatsapp.Main");
intent.setComponent(cn);
PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.activity_main);
views.setOnClickPendingIntent(R.id.imageView, pending);
appWidgetManager.updateAppWidget(currentWidgetId, views);
。
答案 2 :(得分:1)
我认为这是测试简单功能的好方法。然而,这本书的编号是#34;通过模拟数据库功能可以更好地定义单元测试。 这样,您可以对方法进行单元测试,而无需关心数据库正在做什么。
我通常使用模拟库(包含在3.x中)执行此操作。没有详细介绍其他答案中的详细信息,您可以使用补丁来模拟您正在测试的模型(Person),然后让它返回一些东西。
看看mock-django,它提供了许多与此相关的功能,https://pypi.python.org/pypi/mock-django和https://docs.python.org/3/library/unittest.mock.html
对于Python 3,我无法对此进行测试(并且我会更加明确地说明这一点)。在单元测试类中,您可以创建这样的测试。
# first patch your class
@patch('my_app_name.models.Person')
def test_my_person(self, person_mock)
person_mock.objects = MagicMock()
person_mock.objects.configure_mock(get.return_value='guy_number_1')
# then you can test your method. For example if your method change the guy name.
self.assertEquals(my_method('guy_number_1'), 'GUY_NUMBER_1')
代码不是最好的,但你的想法是你在嘲笑数据库,所以如果你的数据库连接刹车,你的单元测试不应该(因为你应该没有测试) Django功能也不是你的数据库连接。)
这在我进行自动构建和测试时非常有用,无需部署测试数据库。然后,您可以添加集成测试以涵盖数据库功能。
如果不够清楚,我会扩展解释。
有时在mock中忽略的有用的东西是configure方法,side_effect用于模拟异常,有时你需要重新加载模块来应用补丁。
答案 3 :(得分:1)
您可以直接检查查询中的属性,而无需实际获取对象:
class PreSaveTests(TestCase):
def test_pre_save_hook(self):
person = Person(name="Joe")
person.save()
# Confirm that the pre_save hook ran.
# The hook sets person.is_cool to True.
self.assertTrue(
Person.objects.filter(pk = person.pk, is_cool=True).exists()
)
答案 4 :(得分:0)
这个问题有点晚了,但 Django 3.2 中有一个 refresh_from_db()
函数,
所以你可以运行:
person = Person(name="Geof")
person.save()
person.refresh_from_db()
https://docs.djangoproject.com/en/3.2/ref/models/instances/#refreshing-objects-from-database