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
有一个处理 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