In unit testing a class,
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
what is the rationale for setting up a class attribute (#1) instead of an instance attribute (#2)? The difference between class vs static vs instance attributes are clear to me (and are illustrated in many other SO posts), but what's not immediately obvious what the pros/cons or use-cases for each.
(1)
import unittest
class TestProduct(unittest.TestCase):
@classmethod
def setUp(cls):
cls.product = Product("book", 30)
(2)
import unittest
class TestProduct(unittest.TestCase):
def setUp(self):
self.product = Product("book", 30)
CodePudding user response:
Consider this example:
class TestProduct(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.list_a = []
def setUp(self):
self.list_b = []
def test_one(self):
self.assertFalse(self.list_b)
self.list_a.append(1)
def test_two(self):
self.assertFalse(self.list_a)
self.list_b.append(1)
test_two
will succeed if it runs before test_one
, because class attribute list_a
will still be empty. But if it runs after test_one
, it will fail because test_one
appends a value to the shared class attribute.
test_one
, on the other hand, will always pass because even if test_two
runs first, because test_one
sees a fresh empty list created by setUp
immediately before test_one
is called, not the list that test_two
modified.
setUp
is called before every instance method is called. setUpClass
is only called once after the class is defined, but before any test is called.
In your example, it won't matter which you use if Product
instances are immutable or no test method modifies the instance, because every test will see the same value whether it is defined in setUp
or setUpClass
. But when a shared Product
instance is feasible, setUpClass
is more efficient than recreating the same mutable value before every test.
CodePudding user response:
BTW the correct names for class and instance initialization methods are:
class TestProduct(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.product = Product("book", 30)
def setUp(self):
self.product = Product("book", 30)
The difference in that setUp
will be invoked for each test method in TestProduct
. It is intended to reset values of objects which could be changed by some tests. On the other hand, setUpClass
is only invoked once before any test in TestProduct
. It is intended for costly initialization of objects that are never changed in any test.