Pytest:如何模拟django管理命令class方法变量

Pytest: how to mock django management command class method variable

有一个处理 csv 文件的 django 管理器命令。 app/my_app/my_command.py

class Command(BaseCommand):
    def handle(self,  *args, **options):
        path = (os.path.join(os.path.abspath(os.path.dirname(__name__)), 'data.csv'))
        # other logic with file

我正在 pytest 中为它编写测试,问题是我无法理解如何模拟变量 path 来测试访问的不是真实的 data.csv 而是临时的 test.csv 文件

@pytest.fixture
def create_test_csv_file(tmpdir_factory):
    path = tmpdir_factory.mktemp('data').join('test.csv')
    # other logic
    return str(path)

@pytest.mark.django_db
def test_function(mocker, create_test_csv_file):
   # smth like mock_path =  create_test_csv_file  <- NEW CODE HERE
    call_command('my_command')

您可以使 path 成为具有默认值的参数。在测试中你可以传递测试文件的路径。

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument(
            "--path",
            dest="path",
            default=os.path.join(os.path.abspath(os.path.dirname(__name__)), 'data.csv')
        )

    def handle(self, *args, **options):
        path = options.get("path")
        ...

然后在测试中你可以调用call_command('my_command', path=<path>)

你不能模拟局部变量 path,但你可以模拟它的检索来源,这里是从 os.path.join.

src.py

import os

class Command:
    def handle(self):
        path = (os.path.join(os.path.abspath(os.path.dirname(__name__)), 'data.csv'))
        print(path)
        return path

test_src.py

from src import Command


def test_real_path(mocker, tmp_path):
    result = Command().handle()
    assert str(result).endswith("data.csv")  # Real file


def test_mock_path(mocker, tmpdir_factory):
    path = tmpdir_factory.mktemp('data').join('test.csv')
    mocker.patch("os.path.join", return_value=path)  # Or "src.os.path.join"

    result = Command().handle()
    assert str(result).endswith("test.csv")  # Test file
    assert result == path

输出:

$ pytest -q -rP
..
[100%]
================================================================================================= PASSES ==================================================================================================
_____________________________________________________________________________________________ test_real_path ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
/home/nponcian/Documents/data.csv
_____________________________________________________________________________________________ test_mock_path ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
/tmp/pytest-of-nponcian/pytest-15/data0/test.csv
2 passed in 0.06s