2

I'm using a singleton object to manage database connections. I'm running a extense suite of tests that depends on that object. Also I have to test that object too so i have to delete it and check if its __del__ method executes properly.

When I test it, because I deleted the singleton, other tests fail because they can't access it anymore. I need to restore it after deleting it, or avoid deleting it and test the delete method other way. Changing the fixture scope could cause an increase in execution time, so its the last resort.

My singleton is something like this:

class Singleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "singleton_instance"):
            cls.singleton_instance = super().__call__(*args, **kwargs)
        return cls.singleton_instance


class SpecificSingle(metaclass=Singleton):
    def __init__(self):
        self.data = 'some complex data'

    def __del__(self):
        # complex logic before delete the object
        del self.data
        pass

And some tests to simulate mines:

import pytest

@pytest.fixture(scope='session')
def use_the_single():
    single = SpecificSingle()
    yield single
    del single

def test_delete(use_the_single):
    use_the_single.__del__()
    assert(use_the_single not in locals())


def test_something(use_the_single):
    test = use_the_single.data
    assert(test == 'some complex data')
Raulillo
  • 166
  • 1
  • 19
  • It is not clear what you are asking. The tests fail? What's wrong with your code? What is your problem, your question? – sanyassh Sep 10 '19 at 14:21
  • @sanyash My tests fail because when i delete the singleton, the data inside of it executes methods like close() in files and connections. After that, when other tests try to access the object it is destroyed. I want to test delete, without deleting (or restoring it after that) – Raulillo Sep 10 '19 at 14:29

1 Answers1

1

Making a copy of the singleton object with deepcopy grants a separated object with no shared references that could bother with the expected behavior.

from copy import deepcopy

def test_delete(use_the_single):
    copied_single = deepcopy(use_the_single)
    copied_single.__del__()
    assert(copied_single not in locals())

You can check more details of how to copy objects in python here.

As pointed out by Azat be aware of the limitations of deepcopy:

  • Can't copy types like: module, method, stack trace, stack frame, file, socket, window, array, or any similar types.

And remember, you can always define a custom __copy__() or __deepcopy__() in case you need a more exhaustive or complex treatment while copying an object.

Raulillo
  • 166
  • 1
  • 19
  • @AzatIbrakov I have updated the answer, i think that's what you were refering to. Thanks for pointing it out. – Raulillo Sep 10 '19 at 14:48