Django中的Factory Boy和自定义对象

77 阅读2分钟

在Django集成测试中,你正在使用工厂模式创建用户实例和用户资料对象。你使用Factory Boy来创建这些对象,但你想知道与使用自定义对象相比,Factory Boy有什么优势。

huake_00198_.jpg

解决方法:

使用Factory Boy的主要优势在于它使你能够轻松地创建具有正确属性和关系的对象,而无需编写大量重复的代码。这可以节省你大量的时间和精力,尤其是当你需要创建大量对象或具有复杂属性和关系的对象时。

此外,Factory Boy允许你轻松地创建和配置对象工厂,以便能够快速生成所需要类型和数量的对象。这可以使你的测试更加灵活和可维护。

代码示例:

在你的代码中,你展示了如何使用Factory Boy创建用户和用户资料对象:

class UserProfileFactory(DjangoModelFactory):
    FACTORY_FOR = UserProfile

    user = factory.SubFactory('portal.factories.UserFactory', profile=None)

    first_name = factory.Sequence(lambda n: "Joe_%d" % n)
    last_name = factory.Sequence(lambda n: "Schmoe_%d" % n)
    nickname = factory.Sequence(lambda n: "JoeBlow_%d" % n)
    profile_image = factory.LazyAttribute(lambda t: File(open(IMAGE_PATH)))


class UserFactory(DjangoModelFactory):
    FACTORY_FOR = User

    username = factory.Sequence(lambda n: "user_%d" % n)
    password = make_password("password")
    email = factory.Sequence(lambda n: "user_%d@gmail.com" % n)

    profile = factory.RelatedFactory(UserProfileFactory, 'user')

    @classmethod
    def _generate(cls, create, attrs):
        models.signals.post_save.disconnect(user_post_save, sender=User)
        user = super(UserFactory, cls)._generate(create, attrs)
        models.signals.post_save.connect(user_post_save, sender=User)
        return user

你还可以使用Data类来生成用于测试的数据

class Data(object):
    def __init__(self):
        self.IMAGE_PATH = os.path.join(os.path.dirname(__file__),
                                       '../../test_files/test_images/image.jpeg')
        self.profile_image = File(open(IMAGE_PATH))

    def get_profile_update(self, user):
        return {'first_name': 'Jeff',
                'last_name': 'Lebowski',
                'nickname': 'The Dude',
                'profile_image': self.profile_image,
                'user': user.pk,}

    def and_so_on(self):
        continues...

然后,你可以在集成测试中使用这些对象和数据:

class PortalTestCase(TestCase):
    """Shortened and simplified"""
    def test_edit_profile_post(self):
        user = UserFactory.create()
        login_bool = self.client.login(username=user.username,
                                       password=self.data.get_password())
        data = self.data.get_profile_update(user)
        response = self.client.post(reverse(self.get_edit_profile()),
                                data=data,
                                follow=True)
        success_url = 'http://testserver%s' % reverse(self.get_portal())
        template_name = self.get_portal_template()
        content_text_img = 'src="/' + user.get_profile().profile_image.url + '"'
        self.assertRedirects(response, success_url)
        self.assertTemplateUsed(response, template_name)
        self.assertContains(response, content_text_img)

通过使用Factory Boy,你能够轻松地创建具有正确属性和关系的对象,并能够快速生成所需要类型和数量的对象,这可以节省你大量的时间和精力,提高测试的灵活性和可维护性。