使用 unittest.TestCase 个实例的 `setUp` 和 `tearDown` 的不同实现
Use different implementations of `setUp` and `tearDown` of unittest.TestCase instances
我想 运行 一组不同条件下的测试,因此在两个不同的 TestCase
派生的 class 之间共享这些测试。
一个创建自己的独立会话,另一个附加到现有会话并在其中执行相同的测试。
我想我在用它测试 API 时有点滥用 unittest
框架,但感觉它与最初的目的并不太远。我现在还好吗?
我一起破解了一些东西并得到了 运行ning。但是这样做的方式,感觉不太对,恐怕迟早会出问题。
这些是我的解决方案遇到的问题:
当简单地 运行 将事物与 PyCharm 连接而不限制测试时,它不仅尝试 运行 预期的 StandaloneSessionTests
和 ExistingSessionTests
还有 GroupOfTests
这只是集合,没有会话,即执行上下文。
我可以 不是 运行 GroupOfTests
不从 TestCase
推导那个,然后 PyCharm 抱怨它不知道 assert...()
函数。这是正确的,因为 GroupOfTest
只能在 运行 时间接访问这些函数,而派生的 class 也继承自 TestCase
。来自 C++ 背景,这感觉就像黑魔法,我认为我不应该这样做。
我尝试将会话创建 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 引发错误。
我想 运行 一组不同条件下的测试,因此在两个不同的 TestCase
派生的 class 之间共享这些测试。
一个创建自己的独立会话,另一个附加到现有会话并在其中执行相同的测试。
我想我在用它测试 API 时有点滥用 unittest
框架,但感觉它与最初的目的并不太远。我现在还好吗?
我一起破解了一些东西并得到了 运行ning。但是这样做的方式,感觉不太对,恐怕迟早会出问题。
这些是我的解决方案遇到的问题:
当简单地 运行 将事物与 PyCharm 连接而不限制测试时,它不仅尝试 运行 预期的
StandaloneSessionTests
和ExistingSessionTests
还有GroupOfTests
这只是集合,没有会话,即执行上下文。我可以 不是 运行
GroupOfTests
不从TestCase
推导那个,然后 PyCharm 抱怨它不知道assert...()
函数。这是正确的,因为GroupOfTest
只能在 运行 时间接访问这些函数,而派生的 class 也继承自TestCase
。来自 C++ 背景,这感觉就像黑魔法,我认为我不应该这样做。
我尝试将会话创建 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 引发错误。