Python 如何重用 Mock 以避免多次编写 mock.patch?

标签 python python-3.x flask mocking python-mock

给定如下代码:

import flask
import time

app = flask.Flask(__name__)

def authorize():
    print('starting authorize io')
    time.sleep(1)
    print('done authorize io')

class BlockingIo():
    def __init__(self, n):
        self.n = n
    def do(self):
        print('starting blocking io')
        time.sleep(1)
        print('ending blocking io')

@app.route('/', methods=['GET'])
@app.route('/<int:n>/', methods=['GET'])
def foo(n=1):
    authorize()
    b = BlockingIo(n)
    b.do()
    return str(n), 200

#app.run(port=5000)

我希望能够为 GET/n/ 编写多个测试,每个测试都模拟 authorizeBlockingIO(n):

app.testing = True
testapp = app.test_client()

import unittest
from unittest import mock

mock.patch('__main__.authorize')

class TestBlockingIo(unittest.TestCase):
    @mock.patch('__main__.authorize')
    @mock.patch('__main__.BlockingIo.do')
    def test_1(self, m, m2):
        r = testapp.get('/1/')
        self.assertEquals(r.data, b'1')
    @mock.patch('__main__.authorize')
    @mock.patch('__main__.BlockingIo.do')
    def test_2(self, m, m2):
        r = testapp.get('/2/')
        self.assertEquals(r.data, b'2')

unittest.main()

但是,我不想一遍又一遍地写出@mock.patch装饰器。

我知道我们可以使用类装饰器,我可以子类化以提高可重用性:

@mock.patch('__main__.authorize')
@mock.patch('__main__.BlockingIo.do')
class TestBlockingIo(unittest.TestCase):
    def test_1(self, m, m2):
        r = testapp.get('/1/')
        self.assertEquals(r.data, b'1')
    def test_2(self, m, m2):
        r = testapp.get('/2/')
        self.assertEquals(r.data, b'2')

但是,这会强制类中的所有测试函数为每个模拟采用一个额外的参数。如果我在此类中有不需要模拟 BlockingIoauthorize 的测试怎么办?

我想我想要的是一种执行以下操作的方法:

m = mock.something('__main__.authorize')
m2 = mock.something('__main__.BlockingIo.do')    

class TestBlockingIo(unittest.TestCase):
    def test_1(self):
        r = testapp.get('/1/')
        self.assertEquals(r.data, b'1')
    def test_2(self):
        r = testapp.get('/2/')
        self.assertEquals(r.data, b'2')

如何重用我的 @mock.patch('__main__.authorize')@mock.patch('__main__.BlockingIo.do') 以避免重复我自己通过了测试?

最佳答案

你可以使用 patches并在 setUp block 中重用它们。

补丁很好,因为您可以在完成测试后“取消打补丁”,这意味着您不会永远模拟某些东西,因为其他一些测试可能需要在真实代码上运行。

在上面的链接中,您将看到以下代码:

>>> class MyTest(TestCase):
...     def setUp(self):
...         patcher = patch('package.module.Class')
...         self.MockClass = patcher.start()
...         self.addCleanup(patcher.stop)
...
...     def test_something(self):
...         assert package.module.Class is self.MockClass
...

它工作正常,但我真的不喜欢为每个调用 patch()start()addCleanup()补丁。

您可以轻松地将其纳入可在测试类中重用的基类中:

class PatchMixin:

    def patch(self, target, **kwargs):
        p = mock.patch(target, **kwargs)
        p.start()
        self.addCleanup(p.stop)

class TestBlockingIo(unittest.TestCase, PatchMixin):

    def setUp(self):
        self.patch('__main__.authorize')
        self.patch('__main__.BlockingIo.do')

    def test_1(self):
        r = testapp.get('/1/')
        self.assertEquals(r.data, b'1')

    def test_2(self):
        r = testapp.get('/2/')
        self.assertEquals(r.data, b'2')

关于Python 如何重用 Mock 以避免多次编写 mock.patch?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57299968/

相关文章:

python - 引用列表的一部分,就好像它是列表本身一样

python - OpenCV cv2.seamlessClone中的错误

python-3.x - ImportError:没有名为传输的模块(Paramiko,Python 3.2.5)

python - 在一个函数中为另一个函数设置变量

python - 没有返回值的多处理池?

python - 设置为开发人员模式时,Flask应用程序无法在cygwin上运行

python - 路线不存在

python - 如何为数据框的特定子集绘制图表

python - 条件表达式/三元运算符

postgresql - psycopg2无法连接到dockerized Python-Flask应用程序中的postgres数据库