0

I started with another question where it was suggested to use fixtures in pytest

I am trying to figure out if fixtures can reside in a standalone class. The examples over the net have them as standalone functions or inherited from another class

My usecase

Why I need them to be standalone ?

I have a class which would connect to external directory server(like LDAP). This class would have fixtures to create/delete objects in the directory server.

Multiple LDAP test classes should be able to use the ExternalDirectory class and connect to different LDAP directory servers

- external_server.py

import ldap
import pytest

class ExternalDirectory(object):
  def __init__(self, creds):
    self.connection = #connect to LDAP server

  @pytest.fixture
  def create_user(self):
    user = []
    def _create_user(self, user_name):
      #create user in ldap
      user.append(user_name)

    yield _create_user
    #delete user list

  #More fixtures of such kind

  def utility_method1(self):
    # some util method

  #More such util methods

The test class will use this class

- test_ldap_users.py

import ExternalDirectory

class TestLdapUser(object):
  @classmethod
  def setup_class(cls):
    #Fetch credentials from some YAML
    cls.ldap_connection = ExternalDirectory(creds)

  def test_ldap_user_create(self, <need-to-call-create-user-fixture-here>):
    create_user('some-user-name')
    ...

The Issue

But I am unable to call the fixture here in the testcase. Infact, I can't figure out how to even call them :)

Alternate approach

To inherit the ExternalDirectory class. But then I'll need to remove __init__ and move it to setup_class for ExternalDirectory, then call setup_class in TestLdapUser.

Limitation in the alternate approach

The connection attribute created in setup_class method of ExternalDirectory will not be exclusive for each of the LDAP test class

Question

What would be a good way to handle this ?

mittal
  • 915
  • 10
  • 29
  • @hoefling I had a chat about pytest, with you, under this thread https://stackoverflow.com/questions/56793857/python-unittest-separate-setup-method-for-each-test and now I am stuck with this requirement. Any suggestions ? – mittal Dec 10 '19 at 17:57

1 Answers1

0

There is an approach I am using currently, but I don't like it

class LDAPFixtures(object):

    @classmethod
    def setup_class(cls, init_data):
        cls.connection = LDAPConnectionInit(init_data)      

    @pytest.fixture
    def create_and_delete_ou(self):
        ou_list = []

        def _create_organizational_unit(ou_name):

            # Code to create an OU
            ou_list.append(ou_name)

            yield _create_organization_unit

            # Code to delete OU

class TestLDAPConnections(LDAPFixtures):
    def test_ou_1(self, create_and_delete_ou):
      # Do something
      ...

      # Now call the fixture
      create_and_delete_ou(random_ou_name)

      # Continue to do something and conclude the test

Why I don't like it ??

I need to create multiple LDAP objects to different servers, so I wish to implement the __init__, create multiple objects for each LDAP connection, then call the fixtures from that object.

So, instead of inheritance I need composition relation. So something like this would be cool

class TestServer():
   @classmethod
   def setup_class(cls):
       cls.ldap1 = LDAPConnection()

   def test_LDAP1(self):
       # Some operations
       ...

       # Call fixture
       cls.ldap1.create_n_delete_user()

       # Continue and conclude the test

class LDAPConnection(LDAPFixtures):
    def __init__(self):
        self.ldap_conn = # some LDAP initialization

    def create_n_delete_user(self):
        # Some way to invoke fixture, give the control
        # back to testcase to continue, then back to fixture
        # after yield, for cleanup

class LDAPFixtures():
    @pytest.fixture
    def _create_and_delete_user(self):
        # Create user

        yield

        # Delete user
mittal
  • 915
  • 10
  • 29