Given code like the following:
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)
I want to be able to write several tests for GET /n/
, each of which mocks authorize
and BlockingIO(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()
However, I do not want to write out @mock.patch
decorator over and over again.
I know we can use a class decorator, and I can subclass for more reusability:
@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')
But, this forces all the test functions in the class to take one extra argument for each mock. What if I have tests in this class that do not need mocks for BlockingIo
or authorize
?
I suppose what I would like is a way to do the following:
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')
How can I reuse my @mock.patch('__main__.authorize')
and @mock.patch('__main__.BlockingIo.do')
to avoid repeating myself through the tests?