Home > Back-end >  Pytest: how to mock django management command class method variable
Pytest: how to mock django management command class method variable

Time:09-16

There is a django manager command that handles the csv file. 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

I am writing a test for it in pytest, the problem is that I can not understand how to mock the variable path to test accessed not the real data.csv but a temporary test.csv file

@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')

CodePudding user response:

You can make path an argument with a default value. In the test you can pass the path to the test file.

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")
        ...

Then in tests you can call call_command('my_command', path=<path>)

CodePudding user response:

You can't mock the local variable path, but you can mock where it was retrieved from, which here is from 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

Output:

$ 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
  • Related