我想在不同条件下运行一组测试,因此在两个不同的TestCase
派生类之间共享这些测试。一个创建自己的独立会话,另一个连接到现有会话并在那里执行相同的测试。
我猜我在使用它测试API时有点滥用unittest
框架,但它并不觉得它与它的原始目的相差太远。我到目前为止好吗?
我把一些东西混在一起,让它运行起来。但它的做法,感觉不对,我害怕迟早会引起问题。
这些是我的解决方案存在的问题:
StandaloneSessionTests
和ExistingSessionTests
,还尝试运行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()
我不确定使用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
作为文件名!
你可以通过使用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引发错误。