[英]Use different implementations of `setUp` and `tearDown` of unittest.TestCase instances
I want to run a set of tests under different conditions and therefore share these tests between two different TestCase
-derived classes. 我想在不同的条件下运行一组测试,因此在两个不同的
TestCase
派生类之间共享这些测试。 One creates its own standalone session and the other attaches to an existing session and executes the same tests in there. 一个创建自己的独立会话,另一个连接到现有会话并在其中执行相同的测试。
I guess I'm kind of abusing the unittest
framework when testing an API with it but it doesn't feel like it's too far from its original purpose. 我猜想我在用它测试API时会滥用
unittest
框架,但感觉它与最初的目的并不太远。 Am I good so far? 到目前为止我还好吗?
I hacked a few things together and got it kind of running. 我一起砍了几件事,并使其运行起来。 But the way it's done, doesn't feel right and I'm afraid will cause problems sooner or later.
但是这样做的方式并没有感觉正确,恐怕迟早会引起问题。
These are the problems I have with my solution: 这些是我的解决方案所遇到的问题:
When simply running the thing with PyCharm without limiting the tests, it attempts to run not only the intended StandaloneSessionTests
and ExistingSessionTests
but also GroupOfTests
which is only the collection and has no session, ie execution context. 当简单地使用PyCharm运行事物而不限制测试时,它不仅尝试运行预期的
StandaloneSessionTests
和ExistingSessionTests
,而且尝试运行GroupOfTests
,后者只是集合,没有会话,即执行上下文。
I can make it not run GroupOfTests
by not deriving that one from TestCase
but then PyCharm complains that it doesn't know about the assert...()
functions. 我可以通过不从
TestCase
派生一个GroupOfTests
来使其不运行,但是PyCharm抱怨它不知道assert...()
函数。 Rightly so, because GroupOfTest
only gets indirect access to these functions at runtime when a derived class also inherits from TestCase
. GroupOfTest
,因为当派生类也继承自TestCase
时, GroupOfTest
仅在运行时间接访问这些函数。 Coming from a C++ background, this feels like black magic and I don't think I should be doing this. 来自C ++背景,这感觉就像是黑魔法,我认为我不应该这样做。
I tried passing the session creation classes to the constructor of GroupOfTests
like this: __init__(self, session_class)
. 我尝试将会话创建类传递给
GroupOfTests
的构造函数,例如: __init__(self, session_class)
GroupOfTests
__init__(self, session_class)
。 But this causes problems when the unittest
framework attempts to instantiate the tests: It doesn't know what to do with the additional __init__
parameter. 但是,这会导致问题时,
unittest
框架尝试实例测试:它不知道如何处理额外做__init__
参数。
I learned about @classmethod
, which seems to be a way to get around the "only one constructor" limitation of Python but I couldn't figure out a way to get it running. 我了解了
@classmethod
,这似乎是解决Python“仅一个构造函数”限制的一种方法,但我想不出一种使它运行的方法。
I'm looking for a solution that lets me state something as straightforward as this: 我正在寻找一种解决方案,使我可以说出这样简单的内容:
suite = unittest.TestSuite()
suite.addTest(GroupOfTests(UseExistingSession))
suite.addTest(GroupOfTests(CreateStandaloneSession))
...
This is what I got so far: 这是我到目前为止所得到的:
#!/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()
I'm not sure if using pytest
is an option for you but if so, here is an example which might do what you want. 我不确定是否可以使用
pytest
,但是如果可以,这是一个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
Output: 输出:
$ 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 =====================================================
If you are actually going to use pytest
you will probably want follow the conventions for Python test discovery rather than using hmm.py
as a filename though! 如果您实际上要使用
pytest
,则可能需要遵循Python测试发现的约定,而不要使用hmm.py
作为文件名!
You can get pycharm to ignore these not existing function by creating abstract methods with raise NotImplementetError
: 您可以通过使用
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
This will let python believe this is an abstract class and will make pycharm raise errors if a subclass doesn't define these functions. 这会让python相信这是一个抽象类,如果子类未定义这些函数,则会使pycharm引发错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.