Лучшая практика ООП для добавления методов в класс с реляционным отображением - PullRequest
1 голос
/ 25 сентября 2019

Предполагая приведенную ниже примерную структуру кода

# 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()
      .... 

Теперь я хотел бы иметь метод, который позволяет назначать «разрешение пользовательской области», и я думаю, что этот метод очень подходит в UserFactory, потому что он напоминает реальныйшаблон мирового уровня.

 def add_user_domain_permission(permission_options, domain):
     ....
     (Invokes RegionUserPermissionFactory to create objects relevant to
      the user)
     ....

Отредактировано 25/09/2019 Является ли лучшим подходом включение методов, связанных с RegionUserPermission, в родительский класс?В моей текущей кодовой базе есть еще несколько классов, которые включают в себя объект пользователя, и лучше ли ООП добавлять их в UserFactory?Это нарушает концепцию инкапсуляции абстракции?

1 Ответ

0 голосов
/ 25 сентября 2019

Идея factory_boy состоит в том, чтобы определить фабрики как соответствующие вашим тестам;набор атрибутов и параметров должен быть определен для обеспечения простого API при написании тестов.Библиотека фокусируется на предоставлении читаемых и поддерживаемых тестов , а не на строгом соблюдении принципов ООП;)

В вашем примере, если для некоторых тестов требуется простой пользователь, а другие хотят присоединить его кВ конкретном регионе вы можете добавить вторую фабрику, выделенную для этого варианта использования, например: 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>>]>
...