1

I am trying to create a unit test for a function that reads every image from a folder and saves them in a list.

Here is a simplified version of the function:

def read_images(directory):

    image_paths = os.listdir(directory)

    images = []
    for im in image_paths:
        images.append(cv2.imread(os.path.join(directory, im)))

    return images

This other question brought me close to the solution, but in my case I want the fake files created to be images (basically, arrays) so I can read them with cv2.imread.

My idea is not having to create any temporary folder and, of course, not having to connect with any external folder or database. Is this possible?

Edit: to be clear, I'd like to not have to create temporary folders, nor temporary image files. I'd like to know if there is a way of telling the program: "There is a folder here, and inside it there are some images/arrays with this shape", but with actually not having to create anything in memory.

Makondo
  • 343
  • 4
  • 16
  • Then skip `imread` and related, and just generate the numpy arrays with the data you need programmatically (which you would need to do anyway). – Dan Mašek Sep 21 '18 at 10:17
  • Should I need to change my function `read_images` to do that? Correct me if I'm wrong, but my idea of unit testing is that I should never need to change the code that I'm testing. Or perhaps you're saying that I should need to refactor my code and make it more modular? – Makondo Sep 21 '18 at 12:07
  • Well, if it is exactly this function you want to test, which uses only `imread`, and therefore can only load images from files (not a database, nor memory or any other source), but you don't want to have files... that's asking for the impossible. I originally assumed you just want to mock the image source. – Dan Mašek Sep 21 '18 at 12:24

2 Answers2

3

If you actually need temporary files, you should check tempfile.

It allows you to create temporary files and directories which provide automatic cleanup, so there are no trash files if you use this while having the opportunity to test what you want.

EDIT

If you don't really want to use tempfiles nor tempfolders, here is another solution concerning your problem:

Generate in-memory image for your test.

from io import BytesIO
from PIL import Image

def create_in_memory_image():
    in_memory_file = BytesIO()
    image = Image.new('RGBA',
                      size=(0, 0),
                      color=(155, 0, 0))
    image.save(in_memory_file,
               'png')
    in_memory_file.name = 'tmp_testing_name.png'
    in_memory_file.seek(0)
    return in_memory_file
Exho
  • 308
  • 1
  • 13
  • Though I agree it's a decent solution, the OP specifically asked for not having to create temporary folders (and presumably image files), which itself is definitely doable. IMO as this is not an answer to the actual question posed, it should probably be a comment on the OP. – alkasm Sep 21 '18 at 10:04
  • Ok, I'm quite new concerning answer in SO, I thought it would be a solution (he only mentioned temporary folder, not temporary files, but your point is relevant and I get it !) – Exho Sep 21 '18 at 10:19
  • Thanks for this approach @Exho. But indeed, this was going to be my plan B in case I couldn't completely mock everything. I'll edit my question to make it clear that, initially, I'm trying not to use image files either. – Makondo Sep 21 '18 at 12:12
  • @Exho no worries, just trying to give you some context on answering vs. commenting. Welcome to Stack Overflow! – alkasm Sep 21 '18 at 16:39
0

how do I mock a fake folder with fake images inside?

def local_cv2_imread():
    # use as a side effect

    return 'fakeImg1'

def test_read_images(self):
    with mock.patch('os.listdir') as mock_listdir:
        with mock.patch('package.module.cv2.imread') as mock_imread:
            mock_listdir.return_value = ['fake_path']
            mock_imread.side_effect = local_cv2_imread
            images = read_images('a_real_path')
            self.assertEqual(images, ['fakeImg1']
Gang
  • 2,658
  • 3
  • 17
  • 38