Home > front end >  Class vs Instance attribute in unit test
Class vs Instance attribute in unit test

Time:01-20

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.

  •  Tags:  
  • Related