'Design pattern for different base classes but almost identical child classes

I write unit tests for different types of users, and my tests are almost the same, but have different base classes. I'm looking at a template method or OOP composition, but I don't know how to properly apply them to my situation.

I have base classes for user roles:


class BaseRoleA:
    def setUp(self):
        """
            Here we init functionality for role A
        """
        self.role = 'admin'
        
    
class BaseRoleB:
    def setUp(self):
        """
            Here we init functionality for role B
        """
        self.role = 'user'

And tests themselves:

class TestForRoleA(BaseRoleA):
    def setUp(self):
        super().setUp()
        self.fruit = 'avocado'

    def test_fruit_for_role_a(self):
        is_correct = self.fruit == 'avocado' and self.role == 'admin' # and identical checks
        return is_correct

class TestForRoleB(BaseRoleB):
    def setUp(self):
        super().setUp()
        self.fruit = 'banana'

    def test_fruit_for_role_b(self):
        is_correct = self.fruit == 'banana' and self.role == 'user' # and identical checks
        return is_correct 

Currently, my refactored versions of the tests are as follows:

class BaseTest:
    @staticmethod
    def setUp(self, fruit):
        self.fruit = fruit
    
    @staticmethod
    def test_fruit_for_role(self, fruit, role):
        is_correct = self.fruit == fruit and self.role == role  # and identical checks 
        return is_correct


class TestForRoleA(BaseRoleA):
    def setUp(self):
        super().setUp()
        BaseTest.setUp(self,'avocado')

    def test_fruit_for_role_a(self):
        return BaseTest.test_fruit_for_role(self.fruit, self.role)

class TestForRoleB(BaseRoleB):
    def setUp(self):
        super().setUp()
        BaseTest.setUp(self, 'banana')

    def test_fruit_for_role_b(self):
        return BaseTest.test_fruit_for_role(self.fruit, self.role)

Are there better and more accurate solutions?



Solution 1:[1]

I think you can do something like this:

class BaseRoleA:
    def set_up(self):
        """
            Here we init functionality for role A
        """
        self.role = 'admin'


class BaseRoleB:
    def set_up(self):
        """
            Here we init functionality for role B
        """
        self.role = 'user'


class BaseTest:
    def set_up(self, base_role_class, fruit):
        self.base_role_class_object = base_role_class()
        self.base_role_class_object.set_up()
        self.fruit = fruit

    def test_fruit_for_role(self, fruit, role):
        return self.fruit == fruit and self.base_role_class_object.role == role


test_object = BaseTest()
test_object.set_up(BaseRoleA, "banana")
print(test_object.test_fruit_for_role("banana", "admin"))
test_object.set_up(BaseRoleB, "avocado")
print(test_object.test_fruit_for_role("orange", "user"))

But I'm not sure this is the best way to write tests.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dmytro Kolupaiev