4

I have a function that raises an exception if the size of a file is too big (> 1MB). I would like to test this function without using a real image. I know it is possible to mock file objects with mock_open but how do I give this fake file a size?

Here is the function I want to test:

def _check_image_size(img_path):
    megabyte = 1048576

    if os.path.getsize(img_path) > megabyte:
        raise ValueError("Image must be less than or equal to 1MB in size.")

So just to reiterate the question in a different way: how to I test this function without using a real file greater than 1MB in size?

P.S. Should I even write a test for this function? I am very much a new developer who doesn't have much experience. Am I going overboard by wanting to test this?

C_Rod_27
  • 61
  • 3
  • 5
  • Near duplicate, but at least applicable: http://stackoverflow.com/questions/19672138/how-do-i-mock-the-filesystem-in-python-unit-tests. This covers most of what is in (and what I considered adding to) my answer. – chepner Feb 06 '16 at 20:56

3 Answers3

4

It's simpler to mock the function itself.

with mock.patch('os.path.getsize', return_value=2*1024*1024)
    try:
        _check_image_size("any arbitrary string")
    except ValueError:
        print "Successfully raised ValueError"
    else:
        print "Did not raise ValueError"

Or, without using the mock library (or something similar), monkey patch the function directly.

import os.path

os.path.getsize = lambda path: return 2*1024*1024
try:
    _check_image_size("any arbitrary string")
except ValueError:
    print "Successfully raised ValueError"
else:
    print "Did not raise ValueError"
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thank you. I knew I had to mock something but I was looking at the wrong thing to mock. Mocking the os.path.getsize worked perfectly. – C_Rod_27 Feb 06 '16 at 20:55
0

If you are testing this, you should mock os.path.getsize instead - the file object mocked with unittest.mock provides a read method, maybe write, close and other file object specific functions - but this function makes a system stat call to an actual file on the filesystem: the mocked file-object can't be "seen" on the filesystem.

So, the thing to do is instead to trust os.path.getsize works, and mock its return values to "True" and "False" to write the tests you want.

jsbueno
  • 99,910
  • 10
  • 151
  • 209
0

mock is your friend

import unittest
from unittest.mock import patch
import os

def _check_image_size(img_path):
    megabyte = 1048576

    if os.path.getsize(img_path) > megabyte:
        raise ValueError("Image must be less than or equal to 1MB in size.")

class Test(unittest.TestCase):

    @patch("os.path.getsize")
    def test_getsize(self, getsize):
        getsize.return_value =  1024 ** 2 + 4

        self.assertRaises(ValueError,lambda: _check_image_size("some path to a big* file"))

I think its OK to test a function like this one.

Yoav Glazner
  • 7,936
  • 1
  • 19
  • 36