如何模拟用Python Flask route()修饰的方法

时间:2017-12-03 18:50:45

标签: flask mocking python-unittest

我需要进行单元测试是否调用由Flask route()修饰的方法。

如果可能的话,我想在没有修改测试的原始代码的情况下执行此操作,因此模拟该方法将完美地满足我的要求。

因此我问这个具体的问题,关于如何模拟一个装饰的请求方法(我想强调这一点,试图避免人们用不太具体的答案浪费时间)......

示例应用jflask.py

from flask import Flask
app = Flask(__name__)
app.config.from_object(__name__)

@app.route('/hello')           # This method represents the code under test.
def hello():                   # I want to assert that this method gets
    return 'Hello, World'      # called without modifying this code.

if __name__ == "__main__":
    app.run()

在单元测试中,我使用@patch()来模拟方法,所以我可以断言它被调用,但断言失败了。即当我期望它时,模拟方法不被调用。

样本单元测试test_hello.py

import unittest
import jflask
from unittest.mock import patch

class jTest(unittest.TestCase):
    def setUp(self):
        #jflask.app.testing = True
        self.app = jflask.app.test_client()

    @patch('jflask.hello')                # mock the hello() method
    def test_hello(self, mock_method):
        rv = self.app.get('/hello')
        mock_method.assert_called()    # this assertion fails

我做错了什么?

背景

有关我正在尝试测试的实际行为的一些背景信息 (因为上面只是一个浓缩的测试用例,并且可能看起来并不完全合理)。

在实际代码中我是单元测试,有一个before_request()处理程序 为应用程序安装。在处理每个请求之前,Flask会调用它 在某些情况下,此处理程序已设计为返回响应值 导致Flask请求处理停止(在此应用程序的情况下,此功能用于集中验证请求参数),以便通常的路由请求处理程序(故意)不会被调用。

我的单元测试需要声明请求处理已停止 或继续,视情况而定。 因此,我的测试需要模拟真实的请求处理程序并断言是否 是否被召唤。

2 个答案:

答案 0 :(得分:0)

这有点hacky但你可以注射一个记录器。

@app.route(...):
def hello(logger=None):
  logger = logger or self.logger
  logger.info(...)
  return ...

def test_...(self):
  logger = MagicMock()
  self.app.get(logger)
  self.assertTrue(logger.info.called)

答案 1 :(得分:0)

from functools import wraps
import logging
from datetime import datetime
logging.basicConfig(filename=datetime.now().strftime('%d_%m_%Y.log'),level=logging.INFO)

def logger_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        logging.info(f.__name__  + ' was called')   
        return f(*args, **kwargs)
    return decorated 

@app.route('/hello')
@logger_required
def hello():                   # I want to assert that this gets called
    return 'Hello, World'