如何为特定方法类模拟/修补内部方法?

问题描述 投票:0回答:1

目标:我正在尝试在应用程序中进行端到端测试。所以我想模拟外部通信来测试所有流程。

业务问题

  • Bar
    等效类:我有一个发送请求的类。

    1. bar_method -> send_request
  • Foo
    等效类:是我的用户类,它构建数据以发送请求。

    • method_that_use_bar_function -> create_user
    • method_that_use_bar_function_too -> get_user
  • runner
    等价物:是执行用户某些操作的作业

再现性

为了简化测试开发,我构建了具有类似结构的代码来重现场景:

# / (root folder)
from src.foo import Foo

def method_to_run_all_my_code():
    my_foo = Foo()
    res1 = my_foo.method_that_use_bar_function()
    res2 = my_foo.method_that_use_bar_function_too()
    return res1 + res2


if __name__ == '__main__':
    method_to_run_all_my_code()

# src/foo.py
from .bar import Bar

class Foo:
    def __init__(self) -> None:
        self.bar = Bar()
    
    def method_that_use_bar_function(self):
        result = self.bar.bar_method()
        print("[Foo] Use 1 - " + result)
        return "Use 1 - " + result
    
    def method_that_use_bar_function_too(self):
        result = self.bar.bar_method()
        print("[Foo] Use 2 - ", result)
        return "Use 2 - " + result


# src/bar.py
class Bar:

def bar_method(self):
    print("[Bar] this is a real method of bar")
    return "real method"

我想在 bar_method 被

method_that_use_bar_function
(不是
method_that_use_bar_function_too
)调用时模拟它,例如。

我尝试了这些测试,但我还做不到。

# tests/runner_test.py
import unittest
import pytest
from unittest.mock import patch, Mock
from runner import method_to_run_all_my_code


@pytest.mark.skip() # this use the real values
def test_initial():
    res = method_to_run_all_my_code()
    assert "Use 1" in res
    assert "Use 2" in res


@pytest.mark.skip() # this mock Foo method
@patch("src.foo.Foo.method_that_use_bar_function", return_value="Mocked foo function use 1")
def test_mocking_bar_for_use_1(mocked_use_1):
    res = method_to_run_all_my_code()
    print("Final Results: ", res)
    assert "Mocked foo function use 1" in res
    assert "Use 2" in res


@pytest.mark.skip()
@patch("src.foo.Bar.bar_method", return_value="Bar function was mocked") # mock bar method for both use 1 and 2. I don't want this.
def test_mocking_bar_method(mocked_bar):
    res = method_to_run_all_my_code()
    print("Final Results: ", res)
    assert "1 - Bar function was mocked" in res
    assert "2 - Bar function was mocked" in res


@pytest.mark.skip() # this raise error
@patch("src.foo.Foo.method_that_use_bar_function", return_value=Mock(bar_method=Mock(return_value="Bar function was mocked to use 1")))
def test_mocking_bar_for_use_1(mocked_bar_use_1):
    res = method_to_run_all_my_code()
    print("Final Results: ", res)
    assert "Mocked foo function use 1" in res
    assert "Use 2" in res


@pytest.mark.skip() # this raise error
@patch("src.foo.Foo.method_that_use_bar_function.Bar.bar_method", return_value="Bar function was mocked to use 1")
def test_mocking_bar_for_use_1(mocked_bar_use_1):
    res = method_to_run_all_my_code()
    print("Final Results: ", res)
    assert "Mocked foo function use 1" in res
    assert "Use 2" in res


if __name__ == '__main__':
   unittest.main()

有人可以帮助我吗?

python mocking pytest python-unittest pytest-mock
1个回答
1
投票

一个点 测试替身 就是让一个单元测试专注于目标代码 它希望锻炼,而不用担心 协作代码的费用(延迟)或可能的错误, 比如高水平

  • create_user
  • get_user

或低级

send_request
方法。

与“下一层”交互的自动化测试, 例如创建/获取用户, 可以明智地称为“单元”测试。 但是通过一层探测的测试 到包含

send_request
的底层 更恰当地标记为“集成”测试。

改变

send_request
的实施 对于
create_user
,但将其还原为
get_user
的通常行为,看起来像 简单的模拟无法解决的桥梁太远了。 显然你已经考虑过嘲讽
send_request
在单元测试的整个过程中, 并拒绝了这种方法。

听起来你想介绍一些 进入目标代码的公共 API, 以便备用网络传输 (比如嘲笑

send_request
) 可以作为参数提供。

要么,或者你可能想提供 一对模拟方法 每个{生产、测试}环境中的正确事情, without 改变他们调用的支持例程, 比如

send_request
.

© www.soinside.com 2019 - 2024. All rights reserved.