具有模拟响应的测试方法,不创建数据

Test method with a mock response, without create data

我正在使用 unittest 方法测试 createData,它会在我的数据库中创建一些内容。

def createData(self, content):
    logging.info("Creating data...")
    request = requests.post(self.url, data=content)
    if request.status_code == 201:
        logging.info("Data created")
    else:
        logging.error("Data not created")
            
    return request

所以我创建了两个测试:一个是我创建数据失败的 self.assertNotEqual(201, badRequest.status_code),另一个是我成功的 self.assertEqual(201, goodRequest.status_code)。当然,之后,我删除了这个数据。

我想在不创建任何数据的情况下进行此测试。所以我嘲笑这样的回应:

import unittest, logging
from data import Data as data
from unittest.mock import Mock

class TestData(unittest.TestCase):

    def testCreateDataSuccess(self):
        mock_response = Mock()
        mock_response.status_code = 201
        with self.assertLogs() as captured:
            data.createData(data, goodContent).return_value = mock_response
            self.assertEqual(201, mock_response.status_code)
            self.assertEqual(captured.records[1].levelname, 'INFO')

然而,尽管模拟了,但在我的数据库中创建了一个数据。你能告诉我我不明白的地方吗?

感谢您的帮助!

模拟通常使用 mock.patch 应用。您要模拟的是 requests.post 的响应,而不是 createData 的响应。弄清楚在哪里模拟可能非常棘手。本指南可以帮助 (https://alexmarandon.com/articles/python_mock_gotchas/)

您可能需要修改导入被测代码的方式,以便能够在正确的位置进行模拟。

import unittest, logging
import data  # We are importing the entire module. This will let us patch in the correct location
from unittest.mock import Mock

class TestData(unittest.TestCase):

    def testCreateDataSuccess(self):
        mock_response = Mock()
        mock_response.status_code = 201
        # using mock.patch, we can replace the response from requests.post with our mock value. `requests` is imported in the `data` module so we mock `data.requests`
        with mock.patch(data.requests.post, return_value=mock_response):
            with self.assertLogs() as captured:
                data.Data.createData(data, goodContent)
                # self.assertEqual(201, mock_response.status_code) This line does not actually do anything - it's just testing that our mock has the status code we set. But we already know that, because we set it just a few lines ago. 
                self.assertEqual(captured.records[1].levelname, 'INFO')

好吧,我找到了解决这个问题的方法:使用补丁装饰器。 我猜它“化解”了数据中的请求 post,用配置的模拟

代替响应
import unittest, logging
from data import Data as data
from unittest.mock import patch

class TestData(unittest.TestCase):
    
    @patch('data.requests.post')
    def testCreateDataSuccess(self, mock_post):
        mock_post.return_value.status_code = 201
        with self.assertLogs() as captured:
            response = data.createData(data, goodContent)
            self.assertEqual(201, response.status_code)
            self.assertEqual(captured.records[1].levelname, 'INFO')