Python 标准库 unittest 不同遮掩方式的比较

背景

最近在搞 TDD , 有些 mock 的写法怕后面忘记了,在这里记录下现在针对 unittest 的一些心得。


目前针对 unittest 的 mock 最佳实践

假设我们有一个 dog.py 的代码,它的内容如下

class Dog(object):
    def get_name(self):
        return "dog"


def fun():
    return "123"

那么它同级目标下 test_dog.py 这样写看起来比较好

from unittest.mock import MagicMock, patch
from unittest import TestCase

from . import dog


class TestDogTestCase(TestCase):
    def test_dog_a(self):
        """
        方法一:
            直接使用 patch 来遮掩目标方法,它有一个问题如果后面我们的文件名变了,路径变了都要调整这个字符串非常不方便。
        """
        mock_get_name = MagicMock()
        mock_get_name.return_value = "hello"

        with patch("utils.dog.Dog.get_name", mock_get_name):
            d = dog.Dog()
            assert d.get_name() == "hello"

    def test_dog_b(self):
        """
        方法二:
            使用 patch.object 来遮掩目标方法,这样字符串就只包括方法名了,对于源文件目标的变更就不影响测试用例了,所以这个相对友好一些。
        """
        mock_get_name = MagicMock()
        mock_get_name.return_value = "hello"

        with patch.object(dog.Dog, "get_name", mock_get_name):
            d = dog.Dog()
            assert d.get_name() == "hello"

    def test_dog_c(self):
        """
        方法三:
            把模块也看成对象,这位模块内的函数也就成方法了, 这个就能都统一到 patch.object 一个来解决了,感觉比较友好。
        """
        mock_get_name = MagicMock()
        mock_get_name.return_value = "hello"

        with patch.object(dog, "fun", mock_get_name):
            assert dog.fun() == "hello"
            assert mock_get_name.called == True

posted on 2025-09-30 23:18  蒋乐兴的技术随笔  阅读(13)  评论(0)    收藏  举报

导航