使用patch来模拟一个函数(而不是一个方法)

时间:2015-09-15 01:35:11

标签: python unit-testing mocking

我想做类似以下示例(找到here

的内容
>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
...     thing = ProductionClass()
...     thing.method(1, 2, 3)

然而,这是在method上修补名为ProductionClass的方法。我想在上下文中修补泛型函数。理想情况下看起来像......

with path.something(my_fn, return_value=my_return) as mock_function:
    do_some_other_fn()

my_fndo_some_other_fn内深入调用,因此很难直接嘲笑。这似乎应该是直截了当但我找不到正确的语法

编辑do_some_other_fn生活的模块中,我导入my_fn如下所示

from my_module import my_fn

所以我需要一种方法来告诉mock来自模块外部的补丁。这可能吗?

编辑2 我认为这使我更清楚我在寻找什么

这有效但不理想:

import my_module
with patch('my_module.fn', return_value='hello') as patch_context:
    x = my_module.fn()
    # x now contains 'hello'

但是我宁愿让它像这样(或类似的东西)

from my_module import fn
with patch('my_module.fn', return_value='hello') as patch_context:
    x = fn()
    # x contains real result from real call to fn()

2 个答案:

答案 0 :(得分:4)

您尝试使用from my_module import fn进行修补无效,因为import语句会创建一个本地符号fn,该符号指向fn my_module 所具有的任何值my_module.fn进口时间。您稍后修补了fn,但这并不重要,因为您已经拥有patch的本地副本。

如果包含python调用的文件是主模块(__main__.fn最初加载的文件),您应该可以通过修补from my_module import fn with patch('__main__.fn', return_value='hello') as patch_context: x = fn() 来执行此操作:

patch

如果包含__main__调用的文件作为模块从主模块加载,则patch无法正常工作,您需要传递包含该模块的模块的绝对模块名称您的patch致电__main__而不是/*The MIT License (MIT) Copyright (c) 2014 https://github.com/kayalshri/ Permission is hereby granted.... .... */ (function($){ $.fn.extend({ tableExport: function(options) { var defaults = { separator: ',', ignoreColumn: [], tableName:'yourTableName', type:'powerpoint', escape:'true', htmlContent:'false', consoleLog:'false' }; var options = $.extend(defaults, options); var el = this; if(defaults.type == 'powerpoint'){ //console.log($(this).html()); var excel="<table>"; // Header $(el).find('thead').find('tr').each(function() { excel += "<tr>"; $(this).filter(':visible').find('th').each(function(index,data) { if ($(this).css('display') != 'none'){ if(defaults.ignoreColumn.indexOf(index) == -1){ excel += "<td>" + parseString($(this))+ "</td>"; } } }); excel += '</tr>'; }); // Row Vs Column var rowCount=1; $(el).find('tbody').find('tr').each(function() { excel += "<tr>"; var colCount=0; $(this).filter(':visible').find('td').each(function(index,data) { if ($(this).css('display') != 'none'){ if(defaults.ignoreColumn.indexOf(index) == -1){ excel += "<td>"+parseString($(this))+"</td>"; } } colCount++; }); rowCount++; excel += '</tr>'; }); excel += '</table>' if(defaults.consoleLog == 'true'){ console.log(excel); } var excelFile = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:"+defaults.type+"' xmlns='http://www.w3.org/TR/REC-html40'>"; excelFile += "<head>"; excelFile += "<!--[if gte mso 9]>"; excelFile += "<xml>"; excelFile += "<x:ExcelWorkbook>"; excelFile += "<x:ExcelWorksheets>"; excelFile += "<x:ExcelWorksheet>"; excelFile += "<x:Name>"; excelFile += "{worksheet}"; excelFile += "</x:Name>"; excelFile += "<x:WorksheetOptions>"; excelFile += "<x:DisplayGridlines/>"; excelFile += "</x:WorksheetOptions>"; excelFile += "</x:ExcelWorksheet>"; excelFile += "</x:ExcelWorksheets>"; excelFile += "</x:ExcelWorkbook>"; excelFile += "</xml>"; excelFile += "<![endif]-->"; excelFile += "</head>"; excelFile += "<body>"; excelFile += excel; excelFile += "</body>"; excelFile += "</html>"; var base64data = "base64," + $.base64.encode(excelFile); window.open('data:application/vnd.ms-'+defaults.type+';filename=exportData.doc;' + base64data); } function parseString(data){ if(defaults.htmlContent == 'true'){ content_data = data.html().trim(); }else{ content_data = data.text().trim(); } if(defaults.escape == 'true'){ content_data = escape(content_data); } return content_data; } } }); })(jQuery);

答案 1 :(得分:0)

您可以看到类似模块对象的静态方法。要修补模块func中的函数mymodule,您可以使用

patch("mymodule.func", return_value=my_return)

您应该注意Where to patch,如果该函数位于您进行测试的同一模块中,则应使用"__main__.func"作为补丁参数。

patch这样的{p> patch.object可以用作装饰器,上下文或start()stop()方法。

现在,在模块中,您可以从其他模块导入函数,如:

from mymodule import func as foo

您在名为func的新模块中创建了对foo的新引用。 每 在此模块中调用foo的时间,您将使用导入时加载的mymodule.func引用:如果您想更改此行为,则应在新模块中修补foo

为了更清楚,我构建了一个示例,其中mymodule包含funcmodule_a,其中包含mymodule并使用mymodule.func,{{ 1}}使用module_b并使用僵尸from mymodule import func as foofoo

mymodule.func

mymodule.py

def func(): return "orig"

module_a.py

import mymodule def a(): return mymodule.func()

module_b.py

from mymodule import func as foo import mymodule def b_foo(): return foo() def b(): return mymodule.func()

test.py

换句话说,选择修补位置的真正规则是如何在使用修补版本的地方引用该功能。