Search code examples
pythonmockingpython-unittest

Python Mocks for if-else and os Module


I have the following code and I tried every way to mock the entire function, but coverage seems to miss the else block. Searched on SO, but no solution helped my case. Kinda wrapping my head around mocks, and is tough. Any help or rather explanation would help. Thanks.

# module.py (main function in a separate class)

def get_log_filename(filepath, filename, env):
   if os.path.exists(filepath):
      logs = filepath+filename+env+".log"
   else:
      os.mkdir(filepath)
      logs = filepath+filename+env+".log"
   return logs

Test Case below

test_module.py

import unittest
import module
from unittest.mock import Mock, patch, MagicMock

class TestModule(unittest.TestCase):
      
    def setUp(self):
        self.logpath = os.path.join('/home')
        self.logconfigpath = os.path.join('/home/config')
        self.logfile = 'test_case_run'
        self.logdata = module('dev', self.logpath, self.logfile, self.logconfigpath) # because the original module is a class and has __init__
    
    @patch('module.os')
    @patch.object(module, 'get_log_filename', return_value = 'filename.log')
    def test_log_file_name(self, mockpath, mockext):
        mockext.path.exists.return_value = True
        module.get_log_filename()
        self.assertEqual(module.get_log_filename(), "filename.log")


    @patch('module.os')
    @patch.object(module, 'get_log_filename', return_value = 'filename.log')
    def test_log_file_names(self, mockpath, mockos):
        mockos.path.exists.return_value = False
        module.get_log_filename()
        mockos.mkdir()
        self.assertEqual(module.get_log_filename(), "filename.log")

The above test_module succeeds, but coverage does not cover the else block of the main function. Can anyone let me know where i am going wrong and how does this even work?


Solution

  • With @patch.object(module, 'get_log_filename', return_value = 'filename.log') line you are mocking the get_log_filename, that is the function to be tested.

    I've correct the test in this way:

    # module.py (main function in a separate class)
    import os
    
    def get_log_filename(filepath, filename, env):
       if os.path.exists(filepath):
          print(1)
          logs = filepath+filename+env+".log"
       else:
          os.mkdir(filepath)
          logs = filepath+filename+env+".log"
       return logs
    

    Test case below

    #test_module.py
    
    import unittest
    import module
    from unittest.mock import Mock, patch, MagicMock
    import os
    
    class TestModule(unittest.TestCase):
    
        def setUp(self):
            self.logpath = os.path.join('/home')
            self.logconfigpath = os.path.join('/home/config')
    
        @patch('module.os')
        def test_log_file_name(self, mockext):
            mockext.path.exists.return_value = True
            res = module.get_log_filename(self.logpath, "filename.log", self.logpath)
            self.assertEqual(res, "filename.log")
    
    
        @patch('module.os')
        def test_log_file_names(self, mockos):
            mockos.path.exists.return_value = False
            res = module.get_log_filename(self.logpath, "filename.log", self.logpath)
            mockos.mkdir.assert_called_once()
            self.assertEqual(res, "filename.log")
    
    
    PS C:\stack_overflow> coverage report -m
    Name             Stmts   Miss  Cover   Missing
    ----------------------------------------------
    module.py            8      0   100%
    test_module.py      17      0   100%
    ----------------------------------------------
    TOTAL               25      0   100%