对于一组自动化测试,仅运行 setUp 一次

我的 Python 版本是2.6。

我希望只执行一次 test setUp 方法,因为我在那里执行所有测试都需要的操作。

我的想法是创建一个布尔变量,它将在第一次执行后被设置为“ true”,然后禁用对 setup 方法的多个调用。

class mySelTest(unittest.TestCase):
    setup_done = False


    def setUp(self):
        print str(self.setup_done)
            
        if self.setup_done:
            return
        self.setup_done = True
        print str(self.setup_done)

输出:

False


True


--- Test 1 ---


False


True


--- Test 2 ---

为什么没用? 我错过什么了吗?

67811 次浏览

You can use setUpClass to define methods that only run once per testsuite.

Don't try to dedupe the calls to setUp, just call it once.

For example:

class MyClass(object):
...


def _set_up():
code to do one-time setup


_set_up()

This will call _set_up() when the module's first loaded. I've defined it to be a module-level function, but you could equally make it a class method of MyClass.

Place all code you want set up once outside the mySelTest.

setup_done = False


class mySelTest(unittest.TestCase):


def setUp(self):
print str(setup_done)


if setup_done:
return


setup_done = True
print str(setup_done)

Another possibility is having a Singleton class that you instantiate in setUp(), which will only run the __new__ code once and return the object instance for the rest of the calls. See: Is there a simple, elegant way to define singletons?

class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(
cls, *args, **kwargs)
# PUT YOUR SETUP ONCE CODE HERE!
cls.setUpBool = True


return cls._instance


class mySelTest(unittest.TestCase):


def setUp(self):
# The first call initializes singleton, ever additional call returns the instantiated reference.
print(Singleton().setUpBool)

Your way works too though.

Daniel's answer is correct, but here is an example to avoid some common mistakes I found, such as not calling super() in setUpClass() when TestCase is a subclass of unittest.TestCase (like in django.test or falcon.testing).

The documentation for setUpClass() doesn't mention that you need to call super() in such cases. You will get an error if you don't, as seen in this related question.

class SomeTest(TestCase):
def setUp(self):
self.user1 = UserProfile.objects.create_user(resource=SomeTest.the_resource)


@classmethod
def setUpClass(cls):
""" get_some_resource() is slow, to avoid calling it for each test use setUpClass()
and store the result as class variable
"""
super(SomeTest, cls).setUpClass()
cls.the_resource = get_some_resource()

setup_done is a class variable, not an instance variable.

You are referencing it as an instance variable:

self.setup_done

But you need to reference it as a class variable:

mySelTest.setup_done

Here's the corrected code:

class mySelTest(unittest.TestCase):
setup_done = False


def setUp(self):
print str(mySelTest.setup_done)


if mySelTest.setup_done:
return
mySelTest.setup_done = True
print str(mySelTest.setup_done)

If you ended up here because of need to load some data for testing... then as far as you are using Django 1.9+ please go for setUpTestData:

class MyTests(TestCase):


@classmethod
def setUpTestData(cls):
# Set up data for the whole TestCase
cls.foo = Foo.objects.create(bar="Test")


def test1(self):
self.assertEqual(self.foo.bar, 'Test')

I'm using Python 3 and found that the cls reference is also available in the setup method and so the following works:

class TestThing(unittest.TestCase):


@classmethod
def setUpClass(cls):
cls.thing = Thing() # the `thing` is only instantiated once


def setup(self):
self.thing = TestThing.thing # ...but set on each test case instance


def test_the_thing(self):
self.assertTrue(self.thing is not None)

for python >3 you can do it by defining startTestRun,stopTestRun of unittest.TestResult class. answer https://stackoverflow.com/a/64892396/2679740

An extension to the answer above, the following example demonstrates setUp vs setUpClass,

class TT(unittest.TestCase):
A = None


@classmethod
def setUpClass(cls) -> None:
print("init A")
cls.A = 1


def setUp(self) -> None:
print("this is set up")
self.a = 1


def test_a(self):
print("test_a")
print(self.a)
pass


def test_b(self):
print("test_b")
print(self.a)
pass

Gives,

test_a init A
this is set up
test_a
1


test_b
this is set up
test_b
1

Here setUpClass can be used to set up some class variables and is only initiated once albeit with multiple tests. But setUp is initiated every time of each test.