或者,“如何设计数据库模式以便于单元测试?”
顺便说一下,这里有一个非常相似的问题: How to test Models in Django with Foreign Keys
我正在尝试使用TDD方法来处理使用Django框架的项目。我正在创建和测试模型及其功能(保存方法,信号......) 以及依赖于模型的其他高级功能。
我知道单元测试必须尽可能孤立,但我发现自己 使用FactoryBoy为每个测试创建了大量的表和关系,因此我的测试不够强大,因为如果模型中的某些内容发生变化,许多测试可能会被破坏。
如何避免所有这些依赖关系并使测试更清洁?
在实际测试之前,你们有什么建议避免所有样板?
最佳做法是什么?
答案 0 :(得分:13)
没有用于测试的最佳实践列表,它有很多适用于您的以及您正在处理的特定项目。当他说:
时,我同意pyriku您不应该根据您的测试方式设计软件
但是,我会添加,如果你有一个好的模块化软件设计,它应该很容易正确测试。
我最近在我的工作中进行了一些单元测试,我在Python中发现了一些有趣且有用的工具, FactoryBoy 是其中一种工具,而不是准备很多在测试类的setUp()方法中的对象,您可以为每个模型定义一个工厂,并在需要时批量生成它们。
你也可以尝试 Mocker ,这是一个模拟对象的库,因为在Python 一切是一个对象,你也可以模拟函数,如果你有用需要测试一个在一天的特定时间生成X事件的函数,例如,在上午10:00发送消息,你编写一个datetime.datetime.now()的模拟,它总是返回'10:00am'并调用该功能带即模拟。
如果您还需要测试一些前端或者您的测试需要一些人工交互(例如在执行OAuth时),您可以使用 Selenium 填写并提交这些表单。
在你的情况下,要准备与FactoryBoy有关系的对象,你可以尝试覆盖Factory._prepare()方法,让我们用这个简单的django模型来做:
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(User, blank=True, null=True)
# ...
现在,让我们定义一个简单的UserFactory:
class UserFactory(factory.Factory):
FACTORY_FOR = User
first_name = 'Foo'
last_name = factory.Sequence(lambda n: 'Bar%s' % n)
username = factory.LazzyAttribute(lambda obj: '%s.%s' % (obj.first_name, obj.last_name))
现在,假设我想要或需要我的工厂生成包含5个成员的组,GroupFactory应该看起来像这样
class GroupFactory(factory.Factory):
FACTORY_FOR = Group
name = factory.Sequence(lambda n: 'Test Group %s' % n)
@classmethod
def _prepare(cls, create, **kwargs):
group = super(GroupFactory, cls)._prepare(create, **kwargs)
for _ in range(5):
group.members.add(UserFactory())
return group
希望这有帮助,或至少给你一个亮点。在这里,我将留下一些与我提到的工具相关的资源的链接:
工厂男孩:https://github.com/rbarrois/factory_boy
Mocker:http://niemeyer.net/mocker
Selenium:http://selenium-python.readthedocs.org/en/latest/index.html
关于测试的另一个有用的线程:
What are the best practices for testing "different layers" in Django?
答案 1 :(得分:2)
尝试使用Mixer。它比'factory_boy'容易得多,而且功能更强大。您不需要设置工厂,并在需要时获取数据:
from mixer.backend.django import mixer
mixer.blend(MyModel)
答案 2 :(得分:0)
我不确定你是否需要深入 。您不应该根据测试方式来设计软件,而是需要根据您正在使用的工具调整测试方式。
假设您希望获得该级别的粒度,例如在测试某个模型时模拟FK和M2M模型,对吧?像
这样的东西class Invoice(models.Model):
client = models.ForeignKey(Client)
并且在测试中,您只想测试Invoice
模型,而不处理Client
模型。是对的吗?那么,为什么不模拟数据库后端,只测试你的模型应该做什么?
我的观点是你不需要达到那个水平。为模型添加一些测试,例如信号,方法,检查模型创建是否正常工作(如果您信任数据库,甚至可以避免这种情况),当您需要使用外部模型时,只需创建您需要的内容测试的setUp()
方法。
如果你想要,你可以使用Python的模拟库来模拟任何你想要的东西:http://www.voidspace.org.uk/python/mock/。如果您真的想要进行TDD,可以在每次测试中使用它来模拟你的FK,但是如果你改变那个模型,你也需要改变所有的模型。