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

问题描述 投票:0回答:2

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

我猜我在使用它测试API时有点滥用unittest框架,但它并不觉得它与它的原始目的相差太远。我到目前为止好吗?

我把一些东西混在一起,让它运行起来。但它的做法,感觉不对,我害怕迟早会引起问题。

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

  • 当简单地使用PyCharm运行事物而不限制测试时,它不仅尝试运行预期的StandaloneSessionTestsExistingSessionTests,还尝试运行GroupOfTests,它只是集合并且没有会话,即执行上下文。
  • 我可以让它不运行GroupOfTests没有从TestCase得到那个,但然后PyCharm抱怨它不知道assert...()功能。这是正确的,因为当派生类也继承自GroupOfTest时,TestCase只能在运行时间接访问这些函数。来自C ++背景,这感觉就像黑魔法,我不认为我应该这样做。

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

我了解了@classmethod,这似乎是解决Python“只有一个构造函数”限制的一种方法,但我无法想办法让它运行起来。

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

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()
python inheritance mixins python-unittest
2个回答
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
投票

你可以通过使用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引发错误。

© www.soinside.com 2019 - 2024. All rights reserved.