使用模拟对象的困境

时间:2012-04-23 21:58:42

标签: python unit-testing mocking

假设我想声明result采用特定格式,我可以将返回值设置为(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)

要前往return (True, 'Success!')

  1. os.path.exists作为返回值的修补程序True。但是在一个单元测试中,我想跳过这个,如何修补os.path.exists
  2.     if os.path.exists(dest):  # I want to skip this
             shutil.rmtree(dest)
    
    1. 如何修补shutil.move(src, dest)?我只是给True所以它不会产生错误吗?如果我想要它失败并且发现异常怎么办?我该如何模拟呢? (我不会总是知道要捕获哪个例外,使用Exception as e的主要原因)。

    2. 如果我实际传递了这个函数,它是否真的意味着没有捕到异常并且它经历了每一行?或者是因为我设置了'mock_object.return_value =(True,'Success!')?

    3. 我只使用两个依赖项,是否需要修补所有外部依赖项,如(os,sys,math,datetime)?或者,如果我的函数正在使用其他函数(已重构)

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

      感谢。对不起,很长的问题。我真的很想擅长编写单元测试。

1 个答案:

答案 0 :(得分:1)

我必须说,在这个特定的用例中,我认为修补/嘲笑不是最好的替代方案......

对于这个单元测试,我在文件系统中创建一个结构,在磁盘中的该结构上运行算法并检查不同的结果(所有这些都没有模拟os或shutil)。

通常我倾向于使用补丁,主要是在外部设置困难或缓慢时(即:可能需要设置一些外部数据库)或者当它停止测试时(即:打开一些对话框)或我想做什么时否则很难检查的东西(比如实际访问某些缓存的计数)。

除此之外,修补/嘲讽太多让我觉得你的设计存在问题(没有考虑到单元测试),因此,在较小的块中进行测试可能有所帮助。 ..