Mock源码阅读与分析
写单元测试的时候,经常要借助Mock来完成某些替换,鉴于Python的动态性,Python中 写单元测试还是很方便的。但是需要吐槽的是,也是因为Python的动态性,Python的功能 必须要由高覆盖率的测试来保证。
Mock源码以及注释
https://github.com/jiajunhuang/cpython/blob/annotation/Lib/unittest/mock.py
感受
看完mock的代码感觉有两点:
标准库的代码并不是那么“标准” — 并不怎么遵守pep8
标准库的代码测试覆盖率超高
看完mock的代码以后给CPython提交了两个patch,一个是优化了一下写法,一个是修复了 一个bug:
造个小轮子
简单实现一个mock如下:
class Mock:
return_value = NotImplemented
def __new__(cls, *args, **kwargs):
new = type(cls.__name__, (cls, ), {'__doc__': cls.__doc__})
return object.__new__(new)
def __init__(self, return_value):
self.return_value = return_value
def __call__(self):
return self.return_value if self.return_value else None
class PatchObject:
def __init__(self, instance, attr_name, value):
self.attr_origin = getattr(instance, attr_name, None)
self.attr_name = attr_name
self.instance = instance
self.value = value
def __enter__(self):
"""perform the patch"""
mocked = Mock(self.value)
setattr(self.instance, self.attr_name, mocked)
return mocked
def __exit__(self, exc_type, exc_val, exc_rb):
"""unpatch"""
if self.attr_origin:
setattr(self.instance, self.attr_name, self.attr_origin)
else:
delattr(self.instance, self.attr_name)
if __name__ == "__main__":
# test mock
class Foo:
def foo(self):
pass
foo = Foo()
foo.foo = Mock(1)
bar = Foo()
bar.foo = Mock(2)
print(foo.foo(), bar.foo())
# test patch object
baz = Foo()
with PatchObject(baz, "baz", 3) as mocked_baz:
print(mocked_baz())
print(dir(baz))
运行结果:
(1, 2)
3
['__doc__', '__module__', 'foo']
更多文章
本站热门
- socks5 协议详解
- zerotier简明教程
- 搞定面试中的系统设计题
- frp 源码阅读与分析(一):流程和概念
- 用peewee代替SQLAlchemy
- Golang(Go语言)中实现典型的fork调用
- DNSCrypt简明教程
- 一个Gunicorn worker数量引发的血案
- Golang validator使用教程
- Docker组件介绍(二):shim, docker-init和docker-proxy
- Docker组件介绍(一):runc和containerd
- 使用Go语言实现一个异步任务框架
- 协程(coroutine)简介 - 什么是协程?
- SQLAlchemy简明教程
- Go Module 简明教程