2

Can we mock test directory and couple of files in python unit test case?

scan.py:

import re
from pathlib import Path

class Scan():


    def scan_files(self, dir_path, filter_regex=None):
        for item in Path(dir_path).iterdir():
            if not item.is_symlink():
                if item.is_dir():
                    for child_item in self.scan_files(item, filter_regex=filter_regex):
                        yield child_item
                else:
                    if filter_regex is None:
                        yield item
                    elif filter_regex:
                        if re.match(filter_regex, item.name, re.IGNORECASE):
                            yield item
                    else:
                        pass

test_scan.py:

import unittest
from mock import patch
from scan import Scan


class TestScan(unittest.TestCase):
    def setUp(self) -> None:
        """Unit Test default 
        """
        pass

    def instantiate_scan_class(self):
        scan = Scan()

        return scan

    def test_scan_files(self):
        dir_path = "/my/test/path"
        
        # Create the UploadWatchService object
        scan = self.instantiate_scan_class()

        result = scan.scan_files(dir_path=dir_path)
        for item in result:
            print(item)




if __name__ == '__main__':
    unittest.main()

I am running like below

python3 -m unittest discover

I am getting below error:

======================================================================
ERROR: test_scan_files (test_scan.TestScan)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/vcimalap/code/watchservice/src/main/test_scan.py", line 24, in test_scan_files
    for item in result:
  File "/Users/vcimalap/code/watchservice/src/main/scan.py", line 12, in scan_files
    for item in Path(dir_path).iterdir():
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/pathlib.py", line 1160, in iterdir
    for name in self._accessor.listdir(self):
FileNotFoundError: [Errno 2] No such file or directory: '/my/test/path'

Can somebody help me to mock following items, so that I can implement unit test or help me any example unit test for scan.py

 1. mocking directory path
 2. Generating few test files
 3. mocking item.is_symlink()
 4. mocking item.is_dir()

One way is we can user path.object, I guess that is for method calling output to set.

Vidya
  • 547
  • 1
  • 10
  • 26

1 Answers1

0

Create test directories and empty files

Just use tempfile (from standard library).

import tempfile

tempfile.TemporaryDirectory().name  
# output: '/tmp/tmpr6ugakay'

Since these are file operations, I wouldn't suggest you to mock things. Instead, use tempfile to create temporary directories (and files) that will be flushed upon system restart (or according to correspondent system policies).

Similarly to tempfile.TemporaryDirectory, there's a tempfile.NamedTemporaryFile.

tempfile.NamedTemporaryFile(prefix="my_temp_file", suffix=".txt").name  
# output: '/tmp/my_temp_file8aq0dsoo.txt'

Create test files with fake content using Faker

For generating fake content for your test files, you could use Faker.

Faker installation

pip install faker

Faker usage

Imports and initialization

import tempfile
from pathlib import Path

from faker import Faker

FAKER = Faker()

Create a TXT file with fake content

file = Path(tempfile.NamedTemporaryFile(suffix=".txt").name)
file.write_text(FAKER.text())

Create a PNG file with fake content

file = Path(tempfile.NamedTemporaryFile(suffix=".png").name)
file.write_bytes(FAKER.image())

Create a ZIP file with fake content

file = Path(tempfile.NamedTemporaryFile(suffix=".zip").name)
file.write_bytes(FAKER.zip())

Check the faker docs for more.

Create test files with fake content using faker-file

You could also use faker-file, which allows you to have more control of the generated content, supports way more files types (DOCX, PDF and many more), integrates nicely with ORMs (Django, SQLAlchemy) and factory_boy and even supports remote storages (such as AWS S3, Azure Cloud Storage and Google Cloud Storage).

faker-file installation

pip install faker-file[all]

faker-file usage

Imports and initialization

from faker import Faker

from faker_file.providers.docx_file import DocxFileProvider
from faker_file.providers.pdf_file import PdfFileProvider
from faker_file.providers.txt_file import TxtFileProvider
from faker_file.providers.zip_file import ZipFileProvider
# many more formats supported, check the docs

from faker_file.providers.helpers.inner import create_inner_docx_file

FAKER = Faker()
FAKER.add_provider(DocxFileProvider)
FAKER.add_provider(PdfFileProvider)
FAKER.add_provider(TxtFileProvider)
FAKER.add_provider(ZipFileProvider)

Create a TXT file with randomly generated fake content

file = FAKER.txt_file()

Create a TXT file with provided content

file = FAKER.txt_file(content="Lorem ipsum dolor sit amet")

Create a PDF file with randomly generated fake content

file = FAKER.pdf_file()

Create a PDF file with provided content

file = FAKER.pdf_file(content="Lorem ipsum dolor sit amet")

Create a DOCX file with randomly generated fake content

file = FAKER.docx_file()

Create a DOCX file with provided content

file = FAKER.docx_file(content="Lorem ipsum dolor sit amet")

Create a ZIP file with 3 DOCX files inside with randomly generated fake content

file = FAKER.zip_file(
    options={
        "count": 3,
        "create_inner_file_func": create_inner_docx_file,
        "create_inner_file_args": {
            "max_nb_chars": 1_024,
        },
    }
)

Create a ZIP file with 1 DOCX files inside with provided content

file = FAKER.zip_file(
    options={
        "count": 1,
        "create_inner_file_func": create_inner_docx_file,
        "create_inner_file_args": {
            "content": "Lorem ipsum dolor sit amet",
        },
    }
)

Check the faker-file docs for more.

Artur Barseghyan
  • 12,746
  • 4
  • 52
  • 44