C_Rod_27
C_Rod_27

Reputation: 61

How do I mock a file object with a set size?

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?

Upvotes: 4

Views: 5064

Answers (3)

Yoav Glazner
Yoav Glazner

Reputation: 8066

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.

Upvotes: 0

chepner
chepner

Reputation: 531948

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"

Upvotes: 4

jsbueno
jsbueno

Reputation: 110516

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.

Upvotes: 1

Related Questions