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

时间:2018-02-23 20:42:21

标签: python inheritance mixins python-unittest

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

我想我在使用它测试API时会滥用unittest框架,但它并不觉得它离原来的目的太远了。到目前为止我好吗?

我一起砍了几件东西,让它运行起来。但它的做法,感觉不对,我害怕迟早会引起问题。

这些是我的解决方案存在的问题:

  • 当简单地使用PyCharm运行事物而不限制测试时,它不仅会尝试运行预期的StandaloneSessionTestsExistingSessionTests,还会尝试GroupOfTests这只是集合和没有会话,即执行上下文。

  • 我可以通过GroupOfTests不从<{1}}中导出{em>而不是来运行TestCase,但PyCharm抱怨说它不知道assert...() {1}}功能。这是正确的,因为当GroupOfTest派生类也继承自TestCase时,GroupOfTests只能在运行时间接访问这些函数。来自C ++背景,这感觉就像黑魔法,我不认为我应该这样做。

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

我了解了suite = unittest.TestSuite() suite.addTest(GroupOfTests(UseExistingSession)) suite.addTest(GroupOfTests(CreateStandaloneSession)) ... ,这似乎是绕过&#34;只有一个构造函数&#34; Python的局限性,但我无法找到让它运行的方法。

我正在寻找一种解决方案,让我可以说明一些简单明了的事情:

#!/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()

这是我到目前为止所得到的:

{{1}}

2 个答案:

答案 0 :(得分:1)

我不确定使用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作为文件名!

答案 1 :(得分:1)

您可以通过使用raise NotImplementetError创建抽象方法来让pycharm忽略这些不存在的函数:

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相信这是一个抽象类,如果子类没有定义这些函数,它将使pycharm引发错误。