首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

pytest的内置插件盘点 10. unittest

插件路径:_pytest.unittest

实现的 hook

调用的 hook

插件功能

搜集unittest.TestCase的子类,作为测试用例

将setUpClass/ tearDownClass方法转为类级 fixture

将setup_method / teardown_method转为方法级 fixture

创建兼容 unittest 测试报告对象,_pytest.unittest.TestCaseFunction

将unittest.skip的结果改为pytest.skip

代码片段

def pytest_pycollect_makeitem( collector: Union[Module, Class], name: str, obj: object) -> Optional["UnitTestCase"]: # Has unittest been imported and is obj a subclass of its TestCase? try: ut = sys.modules["unittest"] # Type ignored because `ut` is an opaque module. if not issubclass(obj, ut.TestCase): # type: ignore return None except Exception: return None # Yes, so let's collect it. item: UnitTestCase = UnitTestCase.from_parent(collector, name=name, obj=obj) return item

class UnitTestCase(Class): # Marker for fixturemanger.getfixtureinfo() # to declare that our children do not support funcargs. nofuncargs = True

def collect(self) -> Iterable[Union[Item, Collector]]: from unittest import TestLoader

cls = self.obj if not getattr(cls, "__test__", True): return

skipped = _is_skipped(cls) if not skipped: self._inject_setup_teardown_fixtures(cls) self._inject_setup_class_fixture()

self.session._fixturemanager.parsefactories(self, unittest=True) loader = TestLoader() foundsomething = False for name in loader.getTestCaseNames(self.obj): x = getattr(self.obj, name) if not getattr(x, "__test__", True): continue funcobj = getimfunc(x) yield TestCaseFunction.from_parent(self, name=name, callobj=funcobj) class TestCaseFunction(Function): def setup(self) -> None: ... self._testcase = self.parent.obj(self.name) # type: ignore[attr-defined] self._obj = getattr(self._testcase, self.name) def runtest(self) -> None: ... setattr(self._testcase, self.name, self.obj) try: self._testcase(result=self) # type: ignore[arg-type] finally: delattr(self._testcase, self.name) def addSkip(self, testcase: "unittest.TestCase", reason: str) -> None: ... def addSuccess(self, testcase: "unittest.TestCase") -> None: ...

被 unittest 插件处理的前提条件

是 python 文件

有 unittest 模块

是 TestCase 子类

收集用例是使用了 unittest 自己的用例加载器

遍历用例名称

根据名称得到方法对象funcobj

后续会读取funcobj的属性,但不会直接调用

用例执行是使用unittest自己的运行协议

检查是否有跳过标记

实例化TestCase类,并指定测试方法

调用TestCase类的实例对象,执行用例

执行结果由 pytest 收集,所以实现了 result 方法

简评

这个插件实现了 hook,却没有调用什么 hook,说明此插件纯纯是为了 pytest 增加额外的功能

...

插件把 unittest 的setUpClass/ tearDownClass方法转为类级 fixture,

却没有将setUp / tearDown方法转为方法级别 fixture

...

在从unittest.TestCase子类中收集用例方法时,没有自己写代码实现,

而是复用 unittest 的 TestLoader,这样可以尽可能的兼容 unittest 原生的规则

...

同样的,在执行用例时,也是重用 unittest 的 TestCase,这么做有几个好处:

兼容 unittest 原生机制,如 doCleanups

兼容类中实例属性的传递

自动调用 setUp 和 tearDown(所以就不需要转成 fixture 了)

...

如下图所示 unittest 有五个核心组件

pytest 复用了其中的 loader 和 case,用来收集和执行类中的用例。

除此之外的功能,均由 pytest 自行实现

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OGIBLZ1OnzUbWRC6OuLg6rgg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券