如何在单元测试setUp中清除元类实现的Singleton实例
Great question! When you implement a Singleton using a metaclass like your example, all instances are stored in the metaclass's _instances class-level dictionary. To make sure each unittest starts with a clean state, you just need to clear this store (or add a helper method to do it neatly).
Quick Fix: Directly Clear the Metaclass's Instance Store
The simplest approach is to access the _instances attribute of your Singleton metaclass and clear it in your test case's setUp() method:
import unittest class TestMySing(unittest.TestCase): def setUp(self): # Wipe all singleton instances before each test runs Singleton._instances.clear() # Your test methods go here...
This works because _instances is a shared class attribute of the Singleton metaclass. Clearing it guarantees the next call to MySing() will create a brand-new, fresh instance.
More Encapsulated Approach: Add a Reset Method to the Metaclass
For cleaner code and to avoid directly accessing a "private" attribute, you can add a dedicated class method to your Singleton metaclass that handles resetting:
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] @classmethod def reset(cls): """Clear all singleton instances managed by this metaclass.""" cls._instances.clear()
Then in your test's setUp(), just call this method for a more readable workflow:
def setUp(self): Singleton.reset()
Example Test Case
Here's a full working example to demonstrate this in action:
# Your singleton class class MySing(metaclass=Singleton): pass # Test case class TestMySing(unittest.TestCase): def setUp(self): Singleton.reset() def test_first_instance_state(self): inst1 = MySing() inst1.test_data = "hello" self.assertEqual(inst1.test_data, "hello") def test_fresh_instance_after_reset(self): inst2 = MySing() # The new instance shouldn't have the 'test_data' attribute from the previous test with self.assertRaises(AttributeError): _ = inst2.test_data
This ensures every test runs in isolation with a completely fresh singleton instance, so tests won't interfere with each other's state.
内容的提问来源于stack exchange,提问作者Ray Salemi

