python - 使用 unittest 在 Python 中模拟类

标签 python python-3.x python-unittest

我正在尝试使用 unittest.mock 模拟一个类。

我有以下包和模块结构:

  • 服务
    • service_one.py
  • 存储库
    • repository_mongodb.py
  • 测试
    • 服务
      • test_service_one.py

类repository_mongodb.py在类service_one.py中使用(通过导入该类)。

这是文件的代码。

文件repository_mongodb.py

class RepositoryMongoDB:

    def __init__(self):
        self.library = []

    def save(self, thing):
        self.library.append(thing)
        return True

文件service_one.py

from repository.RepositoryBookList import RepositoryBookList

class ServiceRodri:

    def __init__(self):
        self.repository = RepositoryMongoDB()

    def save_service(self, thing):
        # Do validation or something else
        return self.repository.save(thing)

现在我想尝试模拟 ServiceRodri 类,这就是我所做的。

import unittest
from unittest.mock import patch
from service.service_one import ServiceOne

class ServiceOneTest(unittest.TestCase):

    def setUp(self):
        self.service_one = ServiceOne()

    @patch('service.service_one.RepositoryMongoBD')
    def test_get_one_book_if_exists_decorator(self, mock_repo):
        mock_repo.save.return_value = "call mock"
        result = self.serviceRodri.save_service("")
        self.assertEquals("call mock", result)

我希望当我调用 RepositoryMongoBD 类的“save”方法时返回分配给它的结果。但这并没有发生。

我也尝试过这样做。

    @patch('repository.repository_mongodb.RepositoryMongoDB')
    def test_get_one_book_if_exists_decorator(self, mock_repo):
        mock_repo.save.return_value = "call mock"
        result = self.serviceRodri.save_service("")
        self.assertEquals("call mock", result)

但它也不起作用。

但是如果我尝试以这种方式模拟函数save()

    @patch('service.service_one.RepositoryMongoDB.save')
    def test_get_one_book_if_exists_decorator_2(self, mock_repo):
        mock_repo.return_value = "call mock"
        result = self.serviceRodri.save_service("")
        self.assertEquals("call mock", result)

工作正常!!!我明白它的作用是当在 service_one 模块中找到调用 save() 时,它会被模拟替换。

正确的做法是什么? (也是最好的方法)

我是Python世界的初学者。我搜索并阅读了很多帖子,但是显示的所有示例都非常简单(例如 sum() 方法)。我已经用其他语言进行了测试,但从未在 Python 中进行过测试。

最佳答案

如果您坚持使用patch,那么您的最终尝试是正确的方法。

之前的尝试不起作用的原因是因为补丁是在导入后应用的,所以您没有修补您认为是的对象。

我已经使用 patch 很长时间了,但这个问题仍然偶尔会困扰我。因此我建议使用基于简单构造函数的依赖注入(inject)。

在 service_one 中

class ServiceOne:

    def __init__(self, respository):
        self.repository

使用 service_rodri = ServiceRodri(RepositoryMongoDB()) 初始化它,可能在 __init__ 文件或其他文件中。然后在您的测试中,您可以在您的设置中创建此模拟。

class ServiceOneTest(unittest.TestCase):

    def setUp(self):
        self.repository = MagicMock()
        self.service_one = ServiceOne(self.repository)

注意修补与依赖注入(inject):

修补还将测试与程序的导入结构结合起来。这使得严格改变模块结构的安全重构变得更加困难。当您需要在进行更改之前进行一些测试时,它最好与遗留代码一起使用。

关于python - 使用 unittest 在 Python 中模拟类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50025322/

相关文章:

python - 如何有选择地屏蔽通过不安全链接发送的任意数据?

python - Django admin 中的自定义验证

python - 构建 Python 3.7.1 - SSL 模块失败

python - 为什么运行unittest时会出现 "-m"和 "unittest"?

php - 编写 mysql 脚本以在循环中检索数据

python - Pyodbc 查询字符串引号转义

通过子类化 TestCase 进行 Python 参数化单元测试

python - `-m` 在 `python -m unittest` 中代表什么?

python-3.x - 从列表创建多个绘图

python - Tkinter 按钮与网格对齐