使用关系映射向 class 添加方法的更好的 OOP 实践
Better OOP practise to add methods to class with relational mapping
假设下面的示例代码结构
# Returns a region
class RegionFactory:
.....
# Returns a user
class UserFactory():
.....
# Assigns a user with a permission against specific region
class RegionUserPermissionFactory():
user = UserFactory()
permission = PermissionFactory()
....
现在我想要一个允许分配 "user region permission" 的方法,我认为这个方法非常适合 UserFactory,因为它类似于真实世界的 class 模板。
def add_user_domain_permission(permission_options, domain):
....
(Invokes RegionUserPermissionFactory to create objects relevant to
the user)
....
2019 年 9 月 25 日编辑
在父 class 中包含与 RegionUserPermission 相关的方法是否是更好的方法?在我当前的代码库中,还有一些包含用户对象的 classes,将它们添加到 UserFactory 是否更好的 OOP 实践?是否违反了抽象封装的概念?
factory_boy 的想法是定义与您的测试用例相关的工厂;应该定义属性和参数集,以便在编写测试时提供简单的 API。
该库专注于提供 可读和可维护的测试 ,而不是严格遵守 OOP 原则 ;)
在您的示例中,如果某些测试需要一个简单的用户而其他测试需要将其附加到特定区域,您可以添加第二个专用于该用例的工厂,例如 RegionalizedUserFactory
:
class RegionalizedUserFactory(UserFactory):
class Params:
# Tests would call RegionalizedUserFactory(region_code='xxx')
# Setting this as a `Param` means that the `region_code` field won't be passed
# to User.objects.create(...)
region_code = 'asia'
add_user_permission = factory.RelatedFactory(
# Once the `User` is created, call UserPermissionFactory(user=the_user, ...)
UserPermissionFactory, 'user',
# And use this factory's region_code attribute as the code for RegionFactory
permission__region__code=factory.SelfAttribute('....region_code'),
)
这将按如下方式使用:
>>> UserFactory() # No region perms
<User: John Doe, perms=[]>
>>> RegionalizedUserFactory() # Default on asia
<User: John Doe, perms=[<Permission: level=admin, region=<Region: asia>>]>
>>> RegionalizedUserFactory(region_code='mars') # Custom region
<User: John Doe, perms=[<Permission: level=admin, region=<Region: mars>>]>
您还可以决定将 类 合并到一个声明中,使用 factory.Maybe
(有条件地启用基于其他字段的声明):
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
class Params:
region_code = None
add_user_permission = factory.Maybe(
'region_code',
factory.RelatedFactory(
UserRegionPermission, 'user',
permission__region__code=factory.SelfAttribute('....region'),
),
)
第二个工厂:
>>> UserFactory() # No region_code => no perms
<User: John Doe, perms=[]>
>>> UserFactory(region_code='asia')
<User: John Doe, perms=[<Permission: level=admin, region=<Region: asia>>]>
假设下面的示例代码结构
# Returns a region
class RegionFactory:
.....
# Returns a user
class UserFactory():
.....
# Assigns a user with a permission against specific region
class RegionUserPermissionFactory():
user = UserFactory()
permission = PermissionFactory()
....
现在我想要一个允许分配 "user region permission" 的方法,我认为这个方法非常适合 UserFactory,因为它类似于真实世界的 class 模板。
def add_user_domain_permission(permission_options, domain):
....
(Invokes RegionUserPermissionFactory to create objects relevant to
the user)
....
2019 年 9 月 25 日编辑 在父 class 中包含与 RegionUserPermission 相关的方法是否是更好的方法?在我当前的代码库中,还有一些包含用户对象的 classes,将它们添加到 UserFactory 是否更好的 OOP 实践?是否违反了抽象封装的概念?
factory_boy 的想法是定义与您的测试用例相关的工厂;应该定义属性和参数集,以便在编写测试时提供简单的 API。 该库专注于提供 可读和可维护的测试 ,而不是严格遵守 OOP 原则 ;)
在您的示例中,如果某些测试需要一个简单的用户而其他测试需要将其附加到特定区域,您可以添加第二个专用于该用例的工厂,例如 RegionalizedUserFactory
:
class RegionalizedUserFactory(UserFactory):
class Params:
# Tests would call RegionalizedUserFactory(region_code='xxx')
# Setting this as a `Param` means that the `region_code` field won't be passed
# to User.objects.create(...)
region_code = 'asia'
add_user_permission = factory.RelatedFactory(
# Once the `User` is created, call UserPermissionFactory(user=the_user, ...)
UserPermissionFactory, 'user',
# And use this factory's region_code attribute as the code for RegionFactory
permission__region__code=factory.SelfAttribute('....region_code'),
)
这将按如下方式使用:
>>> UserFactory() # No region perms
<User: John Doe, perms=[]>
>>> RegionalizedUserFactory() # Default on asia
<User: John Doe, perms=[<Permission: level=admin, region=<Region: asia>>]>
>>> RegionalizedUserFactory(region_code='mars') # Custom region
<User: John Doe, perms=[<Permission: level=admin, region=<Region: mars>>]>
您还可以决定将 类 合并到一个声明中,使用 factory.Maybe
(有条件地启用基于其他字段的声明):
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
class Params:
region_code = None
add_user_permission = factory.Maybe(
'region_code',
factory.RelatedFactory(
UserRegionPermission, 'user',
permission__region__code=factory.SelfAttribute('....region'),
),
)
第二个工厂:
>>> UserFactory() # No region_code => no perms
<User: John Doe, perms=[]>
>>> UserFactory(region_code='asia')
<User: John Doe, perms=[<Permission: level=admin, region=<Region: asia>>]>