使用 unittest.TestCase 个实例的 `setUp` 和 `tearDown` 的不同实现

Use different implementations of `setUp` and `tearDown` of unittest.TestCase instances

我想 运行 一组不同条件下的测试,因此在两个不同的 TestCase 派生的 class 之间共享这些测试。 一个创建自己的独立会话,另一个附加到现有会话并在其中执行相同的测试。

我想我在用它测试 API 时有点滥用 unittest 框架,但感觉它与最初的目的并不太远。我现在还好吗?

我一起破解了一些东西并得到了 运行ning。但是这样做的方式,感觉不太对,恐怕迟早会出问题。

这些是我的解决方案遇到的问题:

我尝试将会话创建 classes 传递给 GroupOfTests 的构造函数,如下所示:__init__(self, session_class)。但是,当 unittest 框架尝试实例化测试时,这会导致问题:它不知道如何处理额外的 __init__ 参数。

我了解了 @classmethod,这似乎是一种绕过 Python 的 "only one constructor" 限制的方法,但我想不出一个方法来获得它 运行宁.

我正在寻找一种解决方案,让我可以像这样直截了当地陈述:

suite = unittest.TestSuite()
suite.addTest(GroupOfTests(UseExistingSession))
suite.addTest(GroupOfTests(CreateStandaloneSession))
...

这是我目前得到的:

#!/usr/bin/python3

import unittest


def existing_session():
    return "existingsession"


def create_session():
    return "123"


def close_session(session_id):
    print("close session %s" % session_id)
    return True


def do_thing(session_id):
    return len(session_id)


class GroupOfTests(unittest.TestCase):  # GroupOfTests gets executed, which makes no sense.
#class GroupOfTests:  # use of assertGreaterThan() causes pycharm warning
    session_id = None

    def test_stuff(self):
        the_thing = do_thing(self.session_id)
        self.assertGreater(the_thing, 2)

    # Original code contains many other tests, which must not be duplicated


class UseExistingSession(unittest.TestCase):
    session_id = None

    def setUp(self):
        self.session_id = existing_session()

    def tearDown(self):
        pass  # Nothing to do


class CreateStandaloneSession(unittest.TestCase):
    session_id = None

    def setUp(self):
        self.session_id = create_session()

    def tearDown(self):
        close_session(self.session_id)


# unittest framework runs inherited test_stuff()
class StandaloneSessionTests(CreateStandaloneSession, GroupOfTests):
    pass


# unittest framework runs inherited test_stuff()
class ExistingSessionTests(UseExistingSession, GroupOfTests):
    pass


def main():
    suite = unittest.TestSuite()
    suite.addTest(StandaloneSessionTests)
    suite.addTest(ExistingSessionTests)

    runner = unittest.TextTestRunner()
    runner.run(suite())


if __name__ == '__main__':
    main()

我不确定使用 pytest 是否适合您,但如果是这样,这里有一个示例可能会满足您的要求。

import pytest


class Session:
    def __init__(self, session_id=None):
        self.id = session_id


existing_session = Session(999)
new_session = Session(111)


@pytest.fixture(params=[existing_session, new_session])
def session_fixture(request):
    return request.param


class TestGroup:
    def test_stuff(self, session_fixture):
        print('(1) Test with session: {}'.format(session_fixture.id))
        assert True

    def test_more_stuff(self, session_fixture):
        print('(2) Test with session: {}'.format(session_fixture.id))
        assert True

输出:

$ pytest -v -s hmm.py
======================================================= test session starts ========================================================
platform linux -- Python 3.6.4, pytest-3.4.1, py-1.5.2, pluggy-0.6.0 -- /home/lettuce/Dropbox/Python/Python_3/venv/bin/python
cachedir: .pytest_cache
rootdir: /home/lettuce/Dropbox/Python/Python_3, inifile:
collected 4 items                                                                                                                  

hmm.py::TestGroup::test_stuff[session_fixture0] (1) Test with session: 999
PASSED
hmm.py::TestGroup::test_stuff[session_fixture1] (1) Test with session: 111
PASSED
hmm.py::TestGroup::test_more_stuff[session_fixture0] (2) Test with session: 999
PASSED
hmm.py::TestGroup::test_more_stuff[session_fixture1] (2) Test with session: 111
PASSED

===================================================== 4 passed in 0.01 seconds =====================================================

如果您真的要使用 pytest,您可能希望遵循 conventions for Python test discovery 而不是使用 hmm.py 作为文件名!

您可以 pycharm 通过使用 raise NotImplementetError:

创建抽象方法来忽略这些不存在的函数
class GroupOfTests:
    session_id = None

    def test_stuff(self):
        the_thing = do_thing(self.session_id)
        self.assertGreater(the_thing, 2)

    def assertGreater(self, a, b): # Pycharm treats these like abstract methods from the ABC module
        raise NotImplementetError

这会让 python 相信这是一个抽象 class 并且如果子 class 没有定义这些函数,会让 pycharm 引发错误。