django - 在 Django 中模拟模型方法

标签 django unit-testing django-models django-testing django-tests

我刚刚开始使用 Mock 来测试 Django 应用程序,而无需接触数据库。我可以在测试中成功模拟我的模型对象,但我对如何处理涉及对象的模型方法有点困惑。

作为一个例子,我的 models.py 中有这个:

class Skill(models.Model):
   title = models.CharField(max_length=255)
   category = models.ForeignKey(
       SkillCategory, default=None, null=True, blank=True
   )

def __unicode__(self):
    return self.title

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    skill = models.ManyToManyField(Skill, default=None)
    avatar = models.URLField(
        max_length=400, default=None, null=True, blank=True
    )

    def __unicode__(self):
        return self.user.username

    def update_skills(self, cleaned_skills):
        for s in cleaned_skills:
            skill, created = Skill.objects.get_or_create(title=s)
            self.skill.add(skill)

到目前为止,在我的重构测试中我已经这样做了:

class ProfileTestCase(unittest.TestCase):
    def setUp(self):
        # mock user
        self.user = mock.Mock(spec=User)
        self.user.username = "john"
        self.user.email = "johndoe@hotmail.com"
        self.user.password = "pass"
        # mock profile
        self.userprofile = mock.Mock(spec=UserProfile)
        self.userprofile.user = self.user
        # mock skill category
        self.skill_category = mock.Mock(spec=SkillCategory)
        self.skill_category.title = "foo"
        # mock skill
        self.skill = mock.Mock(spec=Skill)
        self.skill.title = "ninja"
        self.skill.category = self.skill_category

    def test_skillcategory_created(self):
        self.assertEqual(self.skill.category.title, 'foo')

    def test_skill_created(self):
        self.assertEqual(self.skill.title, 'ninja')

    ...
    # and so on

在我使用数据库的旧测试中,我用这个来测试我的模型方法:

    ...

    def test_update_skills(self):
        cleaned_skills = ['mysql', 'unix']
        self.userprofile.update_skills(cleaned_skills)
        skills = self.userprofile.skill.values_list('title', flat=True)
        self.assertTrue('mysql' in skills)

我正在绞尽脑汁地思考如何重构这一行:

self.userprofile.update_skills(cleaned_skills)

利用Mock

最佳答案

您可以模拟 get_or_create() 方法以及 skill 关系,以便在不访问数据库的情况下运行测试。

def test_update_skills(self):
    def mock_get_or_create(title):
        return title, True
    mock_skill = set()
    with mock.patch('analytics.models.Skill.objects.get_or_create',
                    mock_get_or_create), \
            mock.patch.object(UserProfile, 'skill', mock_skill):
        userprofile = UserProfile()

        cleaned_skills = ['mysql', 'unix']
        userprofile.update_skills(cleaned_skills)

    self.assertEqual({'mysql', 'unix'}, mock_skill)

我正在帮忙处理 django_mock_queries project这有助于提供一系列 Django 查询集功能,而无需访问数据库。它使我们的许多测试速度更快。

关于django - 在 Django 中模拟模型方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19848375/

相关文章:

python - 向 Django 模型添加动态字段

python - 将不同格式的日期时间传递给 Django 中的 models.DateTimeField?

Django 通用 View UpdateView 重定向 URL 与更新的 slug

python - 覆盖来自第三方应用程序的 URL 模式

html - 当我需要从 WYSIWYG 编辑器呈现 HTML 时如何防止 XSS 攻击?

python - 使用随机主键创建 Django 对象

unit-testing - 使用 ServiceBusTrigger 对 Azure Function 进行单元和集成测试

unit-testing - 在阻止的 spock 测试中抛出 MissingPropertyException

c# - xUnit:如何断言 EventHandler<EventArgs> 类型的其他事件

python - Django 迁移外键 django.db.utils.OperationalError : (1005, "Can' t create table 'asp052mysqlpy.#sql-6ac_56' (errno: 150)") 错误