2013-04-02 42 views
31

我有一个函数我想单元测试包含调用两个其他函数。我不确定如何在正确使用补丁的同时嘲笑两个函数。我提供了一个我下面的意思的例子。当我运行nosetests,测试通过,但我觉得必须有一个更干净的方式来做到这一点,我真的不明白关于f.close()的作品...用补丁嘲笑两个函数单元测试

目录结构如下所示:

program/ 
    program/ 
    data.py 
    tests/ 
    data_test.py 

data.py:

import cPickle 

def write_out(file_path, data): 
    f = open(file_path, 'wb') 
    cPickle.dump(data, f) 
    f.close() 

data_test.py:

from mock import MagicMock, patch 

def test_write_out(): 
    path = '~/collection' 
    mock_open = MagicMock() 
    mock_pickle = MagicMock() 
    f_mock = MagicMock() 
    with patch('__builtin__.open', mock_open): 
     f = mock_open.return_value 
     f.method.return_value = path 
     with patch('cPickle.dump', mock_pickle): 
      write_out(path, 'data') 
      mock_open.assert_called_once_with('~/collection', 'wb') 
      f.close.assert_any_call() 
      mock_pickle.assert_called_once_with('data', f) 

结果:

$ nosetests 
. 
---------------------------------------------------------------------- 
Ran 1 test in 0.008s 
OK 
+1

我觉得我原来的问题不清楚,所以我清理了。我希望这显示我正在寻找更准确的! – cnodell

回答

47

您可以通过使用补丁装饰和嵌套他们,像这样简化您的测试(他们是MagicMock对象默认情况下):

@patch('cPickle.dump') 
@patch('__builtin__.open') 
def test_write_out(mock_open, mock_pickle): 
    path = '~/collection' 
    f = mock_open.return_value 
    f.method.return_value = path 

    write_out(path, 'data') 

    mock_open.assert_called_once_with('~/collection', 'wb') 
    mock_pickle.assert_called_once_with('data', f) 
    f.close.assert_any_call() 

呼叫到MagicMock实例返回一个新MagicMock实例,因此您可以检查返回的值就像其他任何模拟对象一样被调用。在这种情况下,fMagicMock,名为'open()'(尝试打印f)。

+2

在您的建议中,您将介绍两个参数,每个模拟一个参数。 python如何知道哪个是哪个?我没有在文档中找到这个答案。 – steps

+8

装饰者自底向上应用,参数的顺序需要与此匹配。看到这里:http://www.voidspace.org.uk/python/mock/patch.html?highlight=stack#nesting-patch-decorators –

+0

是的,我读过这个,但没有发现它足够清楚。谢谢! – steps

2

下面是关于如何测试使用模拟在create_collection功能提高ConflictError一个简单的例子:

import os 
from unittest import TestCase 
from mock import patch 
from ..program.data import ConflictError, create_collection 


class TestCreateCollection(TestCase): 
    def test_path_exists(self): 
     with patch.object(os.path, 'exists') as mock_method: 
      mock_method.return_value = True 

      self.assertRaises(ConflictError, create_collection, 'test') 

请另见mock docs和迈克尔Foord的真棒introduction to mock

+0

谢谢你甚至试图帮助我。这对我有帮助,但我更关注如何使用补丁模拟多个功能。不幸的是,我的问题没有说清楚。我现在已经清理了这个问题。 – cnodell

21

除了响应@Matti约翰说,你也可以使用patch内部功能test_write_out

from mock import MagicMock, patch 

def test_write_out(): 
    path = '~/collection' 
    with patch('__builtin__.open') as mock_open, \ 
      patch('cPickle.dump') as mock_pickle: 

     f = mock_open.return_value 
     ... 
相关问题