user1012451
user1012451

Reputation: 3433

Dillemma with using mock objects

Suppose I want to assert that result is in a particular format, I might set the return value to something as (True, 'Success')

def batch_move(self, *args, **kwargs):
  ''' 
  Move a batch of files to its respective destinations.
  Return type: tuple (boolean, message)
                      T/F    , 'string' / str(exception)
  '''

  srcs= kwargs.get('srcs', None)
  dests = kwargs.get('dests', None)

  try:
    if srcs and dests:
       # map srcs and dests into dictionary (srcs --> keys, dests --> values)
       src_dest= dict(zip(srcs, dests))     

       for src, dest in src_dest:
         if os.path.exists(src):
           if os.path.exists(dest):
              shutil.rmtree(dest)
           shutil.move(src, dest)   # either way we will proceed to move
         else:
           return (False, '%s does not exist!' % src)
       return (True, 'Success!')

    else:
       return (False, 'Something gone wrong with those kwargs...')
  except Exception as e:
    return (False, e)

In order to get to return (True, 'Success!')

  1. patch os.path.exists with True as return value. But in one unittest I want to skip this, how do I patch that os.path.exists?
    if os.path.exists(dest):  # I want to skip this
         shutil.rmtree(dest)
  1. How do I patch shutil.move(src, dest)? Do I just give True so it doesn't generate error? What if I want the case it fails and caught an exception? How do I simulate that? (I wouldn't always know which exception to catch, the primarily reason to use Exception as e).

  2. If I actually pass the function, does it really mean no exception caught and it went through every single line? Or is it because I set `mock_object.return_value = (True, 'Success!')?

  3. I am only using two dependencies, do I need to patch out all the external dependencies such as (os, sys, math, datetime) all in one? Or if my function is using other functions (which are refactored)

 def f1(*args, **kwargs):
    f2(..)   # use math, plot, datetime
    f3(..)   # use math and datetime
    f4(..)   # use datetime

    ....

Thanks. Sorry for the long questions. I really want to be good at writing unittests.

Upvotes: 4

Views: 391

Answers (1)

Fabio Zadrozny
Fabio Zadrozny

Reputation: 25332

I must say that in this particular use-case, I don't think patching/mocking would be the best alternative...

For this unit-test, I'd create a structure in the filesystem, run the algorithm on that structure in the disk and check for the different outcomes (all without mocking os nor shutil).

Usually I tend to use patching mostly when the external setup is difficult or slow (i.e.: maybe having to setup some external database) or when it would halt the test (i.e.: opening up some dialog) or when I want to do something that's difficult to check otherwise (such as counting if some cache is actually accessed).

Other than that, patching/mocking too much gives me the impression you have a problem in your design (which wasn't done with unit-testing in mind), so, breaking it up in smaller chunks to test may help...

Upvotes: 1

Related Questions