简体   繁体   English

烧瓶单元测试:无法在发布请求中模拟函数

[英]Flask unit-test: Unable to mock a function in a post request

I have the following flask app.我有以下烧瓶应用程序。

# app.py

from flask import Flask, request
from predict import query_sku

app = Flask(__name__)

@app.route("/predict", methods=["POST"])
def predict():
    content = request.json
    max_results = content["resultSize"]
    input_sku_list = content["sku"]

    skus = query_sku(input_sku_list, max_results)
    return {"sku": skus}

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

I wrote a unit-test for it using pytest and tried to mock the query_sku function using unittest.mock .我使用pytest为它编写了一个单元测试,并尝试使用unittest.mock模拟query_sku函数。

import sys
from unittest.mock import Mock

import pytest

import app

def test_api_mocked_model():
    sys.modules["predict"] = Mock()
    from predict import query_sku
    query_sku.return_value = "dummy"

    with app.app.test_client() as client:
        response = client.post('/predict', json={"resultSize":10,"sku": "x"}).json

    assert response == {"sku": "dummy"}
    del sys.modules['predict']

But I was unable to mock that function within the request.但是我无法在请求中模拟该功能。 It just gave the following assertion error.它只是给出了以下断言错误。

>       assert response == {"sku": "dummy"}
E       AssertionError: assert None == {'sku': 'dummy'}
E         +None
E         -{'sku': 'dummy'}

tests/unit_tests/test_api.py:34: AssertionError

How can I get it to work?我怎样才能让它工作?

[EDIT] [编辑]

I added in the query_sku function below.我在下面的query_sku函数中添加了。 Intentionally return a value that is different from the Mock function return_value.有意返回一个与 Mock 函数 return_value 不同的值。

# predict.py
def query_sku(input_sku_list, topn):
    return "actual function"

But the unit-test is still querying from the actual function, as shown below.但是单元测试仍然是从实际功能中查询,如下所示。

assert response == {"sku": "dummy"}
E       AssertionError: assert {'sku': 'actual function'} == {'sku': 'dummy'}
E         Differing items:
E         {'sku': 'actual function'} != {'sku': 'dummy'}
from unittest.mock import MagicMock

def test_api_mocked_model():
     ## sys.modules["predict"] = Mock() ## why sys module ?
    from predict import query_sku
    query_sku = MagicMock(return_value="dummy") # mock directly 
  


    with app.app.test_client() as client:
        response = client.post('/predict', json={"resultSize":10,"sku": "x"}).json

    assert response == {"sku": "dummy"}
    del sys.modules['predict']

Could you try this code ?你能试试这个代码吗?

Actually, the answer above did not work for me.实际上,上面的答案对我不起作用。 Rather than using MagicMock, I used @mock.patch and that worked.我没有使用 MagicMock,而是使用了 @mock.patch 并且效果很好。 And it is less complicated too.而且它也不那么复杂。 For example, in your app.py, you can have an API endpoint that you want to stub out with a mock:例如,在你的 app.py 中,你可以有一个 API 端点,你想用一个 mock 来存根:

app.py应用程序.py

def fetch_nodes(usr, passwd, hostname, node_name):
  sftp_connection = get_sftp_connection(usr, passwd, hostname)
  nodes = sftp_connection.listdir_attr(node_name)
  return nodes

Now in test_app.py, you can stub it out like this:现在在 test_app.py 中,您可以像这样将其存根:

test_app.py test_app.py

from app import app
import unittest
from unittest import mock

class FlaskTest(unittest.TestCase):
  @mock.patch('app.fetch_nodes')
  def test_list_child_nodes(self, mocked):
    tester = app.test_client(self)

    mocked.return_value = []

    response = tester.post("/api/listchildnodes", json={
      'usr': 'test',
      'jwt': 'test',
      'node_name': 'test',
    })

    statuscode = response.status_code
    self.assertEqual(statuscode, 200)
  
if __name__ == "__main__":
  unittest.main()

The important thing is the definition of mock.patch('app.fetch_nodes') which references the fetch_nodes function in app.py and secondly it is passed to the test function as "mocked".重要的是 mock.patch('app.fetch_nodes') 的定义,它引用 app.py 中的 fetch_nodes 函数,其次它作为“模拟”传递给测试函数。 Then we set the return value of "mocked".然后我们设置“mocked”的返回值。 And finally call the flask endpoint.最后调用烧瓶端点。 Now the flask endpoint will use the mock instead of actually hitting an sftp server.现在烧瓶端点将使用模拟而不是实际访问 sftp 服务器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM