如何 mock/patch mocked/patched 对象的 class 变量?

How to mock/patch the class variable of a mocked/patched object?

dir1/a.py是一个class待测。我需要 mock/patch class。

dir1/a.py

from somemodule import get_c

@dataclass
class A:
    x: int
    y: object
    c: ClassVar[C] = get_c()  # get_c() need to be mocked/patched 

test_1.py

@pytest.fixture
def sut() -> A:
    x = 1
    y = Mock()
    return A(x, y)

def test_...(sut):  # get_c() is called
    ''' '''

test_2.py

@patch('dir.a.A')
def test_...():  # get_c() is called
  

如何在测试中mock/patchA.c

因为 c: ClassVar[C] = get_c()dir1/a.py 文件的 top-level 的 A 数据类的声明中,当模块是进口。所以 get_c 将被调用,除非你采取极端措施(实施 custom import loader,或在 import dir1.a 被调用之前修补 dataclass 装饰器,...)。

如果您不希望 get_c 在您的测试中被调用,最好和更简单的解决方案是更改 dir1/a.py 的代码使其不被调用。

如果调用get_c没问题,但是不应该使用上面的方法,那就更简单了:只需替换[=12=的c默认值] 数据类与您自己的一个。

import pytest
import unittest.mock as mocking
from dataclasses import dataclass
from typing import ClassVar, TypeVar


C = TypeVar('C')


def get_c():
    print("`get_c` called")
    return "THING TO MOCK"


@dataclass
class A:
    x: int
    y: object
    c: ClassVar[C] = get_c()


@pytest.fixture
def sut() -> A:
    x = 1
    y = mocking.Mock()
    a = A(x, y)
    a.c = mocking.Mock()   # change the value of `c`
    return a


def test_a(sut):
    assert isinstance(sut.c, mocking.Mock)