The problem is the following, suppose we have this functions:
from PIL import Image
from magiclibrary import perform_some_operation, stack_images
def load_image(path: str):
if isfile(path):
img = Image.open(path)
perform_some_operation(img)
return img
else:
throw FileNotFoundException
def stack_images(paths: List[str]):
imgs = list()
for path in paths:
imgs.append(load_image(path))
return stacks_images(imgs)
Suppose that checking that the path exists is the responsability of the function load_image. We could write two tests, one for a path to an existing image and one to a wrong path. The problem arises with our second function, stack_images.
My research has led me to think that the usual way to deal with this kind of problem is to mock the inner function, and check if it was called. I think that is a bad idea because doing that you are linking the tests to the implementation of the method, and not the use cases. If at any point in the future you want to change the function for whatever reason, the method may still act properly in use cases and in corner cases, but the tests will signal that there is a problem.
The other approach is giving stack_images a list where all paths lead to existing images, and another case where some or all the paths are wrong. IMHO, checking this should not be the responsability for this method, and we already tested that the inner method performs properly when this is the case.
My concern with this second approach is that if load_image wasn't a method, but was just written inline inside stack_images where the call is, stack_images would have the same 2 tests required but we would have 2 tests less, because since load_image is not a method anymore, we don't have to test it.
2 extra tests doesn't seem much, but what if this pattern is repeated across 5 diferent functions to enhance maintainability? Should we test the same 2 cases for the 5 functions? This seems inherently bad for me.
My question is, how I'm supposed to test stack_images?
Edit: I think this is not a duplicate of this question because they talk about mocking the data sources for the top function, but in this case we are not talking about I/O or web functions, we are talking about how to manage the responsabilities of inner functions in a general way, when testing a function that uses this functions in its implementation.