Search code examples
pythonmockingpython-unittest

How to mock the read file function using unittest


I want to mock the read file method using unittest. Need to test read_file() method from the read class. having below class:

class read:
     def read_file():
        result = None
        if os.path.isfile("c:/user/file.txt"):
            result = []
            try:
                file = open("c:/user/file.txt", "r")
                file.close()
            except Exception as e:
                raise error(f"reading file error{"c:/user/file.txt"} - {e}")
        else:
            raise error(f"no such file error{"c:/user/file.txt"}""")
        return result

Tried test for read_file() method:

def test_read_file():

    read_file=[
        "20000, 00000000, 10000, xyz"
    ]
    mock_open = mock.mock_open(read_data=read_file)
    with mock.patch("builtins.open", mock_open):
        reader = read("filename")
        exp_result = read_file()
    assert read_file == exp_result

Solution

  • The class read

    There are some errors in your class read, so I have made the minimum corrections to it and after that I have saved the class read in a file called read.py. The file read.py is as below:

    import os
    
    class read:
    
        #++++++++++++++++++++++++++++++
        # Add this method to your class
        #++++++++++++++++++++++++++++++
        def __init__(self, filename):
            self.filename = filename
    
        # ---> I have add the argument self in the method because it is necessary
        # when you define the method of a class
        def read_file(self):
            result = None
            # ---> the path of the file 'file.txt' is saved in
            # the attribute self.filename
            if os.path.isfile(self.filename):
                result = []
                try:
                    file = open(self.filename, "r")
                    file.close()
                except Exception as e:
                    # ----> raise Exception and not 'error'
                    raise Exception(f"reading file error{self.filename} - {e}")
            else:
                # ----> raise Exception and not 'error'
                raise Exception(f"no such file error {self.filename}")
            return result
    

    Note that I have add the method __init__ to it.
    To try to execute the method read_file() you can use the following code (write it in the same file read.py):

    try:
        file_content = read("c:/user/file.txt").read_file()
        print(file_content)
    except Exception as ex:
        print(ex)
    

    If the file c:/user/file.txt exists you will obtain the following output (empty list because you have set result = []):

    []
    

    If the file c:/user/file.txt doesn't exist you will obtain the following error message (print by the instruction print(ex)):

    no such file error c:/user/file.txt
    

    The test file

    I write a possible test for the method read_file() of the class read in a file called test_read.py saved in the same folder which contains the file read.py. The content of the file test_read.py is:

    import unittest
    from unittest.mock import patch
    from read import read
    
    class MyTestCase(unittest.TestCase):
    
        # ---> here yor test with a bit changes <---
        def test_read_file(self):
            read_file = [
                "20000, 00000000, 10000, xyz"
            ]
            # instantiation of the class read
            reader = read("filename")
            # patching of the method 'read_file'
            with patch.object(reader, 'read_file') as mock_read_file:
                # set the return value of the read_file
                mock_read_file.return_value = read_file
                # call the method read_file()
                exp_result = reader.read_file()
                # check the result
                assert read_file == exp_result
    
    if __name__ == '__main__':
        unittest.main()
    
    

    The test patches the method read_file() setting its return value to the list ["20000, 00000000, 10000, xyz"], so when the method read_file() is executed by the instruction reader.read_file() it returns exactly that list as the test is expecting.

    To execute the previous test do the following steps:

    # go to the folder where are present the 2 files (read.py and test_read.py)
    cd path/to/folder/with/file/test_read.py
    
    # execute the followed command
    python -m unittest discover -v
    

    The output of the test execution is:

    no such file error c:/user/file.txt
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    OK
    

    I hope I have guessed your intentions.