friend,读懂Python的Mock目标库(1),崔成国

当你期望编写强健的代码时,运用测验关于验证程序逻辑是否正确,牢靠以及高效至关重要。可是,测验的价值取决于它能达到这些规范的程度。比方杂乱的逻辑和意料之外的依靠等妨碍都会对编写高质量的测验形成困难。Python中的mock方针库unittest.mock能够协助你处理这些妨碍。

读完本篇文章,你将收成许多:

1. 运用Mock创立Python mock方针

2. 断语你运用的方针是friend,读懂Python的Mock方针库(1),崔成国你期望的

3. 校验并运用Python mock的数据

4. 针对Python mock方针进行装备

你将从mock是什么以及它怎样优化你的测验程序开端。

Mock是什么

一个在测验环境中仿照并替换实在方针的mock方针,它是一个强壮且功用丰厚的东西,能够进步你的测验代码质量。

运用Python模仿方针的一个原因是在测验期间操控代码的行为。

例如,假如你的代码对外发出了一个HTTP恳求,那么只要效劳的运转契合你的预期,测验程序才干依照你的预订办法履行。有时分,外部效劳的暂时改动有或许会导致你的测验蜡烛组件呈现间歇性毛病。

因而,最好是在可控的环境中运转你的测验。运用mock方针替换实践恳求能够答应你以可预知的办法模仿外部请friend,读懂Python的Mock方针库(1),崔成国求效劳的中止以及成功。

有时,你很难测验到代码库的特定区域。这些区域包含except和if句子块等难以满意条件的部分。运用Python mock方针能够协助你操控你的代码履行途径以进入这些区域,并进步你的测验代码覆盖率。

运用mock方针的另一个原因是为了更好的了解你代码中实践运用的方针。你能够发现,Python mock方针包含的数据的用途:

1. 假如你调用了办法

2. 你怎样调用的这个办法

3. 你多久调用一次这个办法

了解mock方针的作用是学习运用mock方针的榜首步。

现在,你将学习怎样运用Python mock方针。

Python mock库

Python的mock方针库是unittest.mock。它供给了一种在测验中引进mock的简略办法。

注:Python 3.3以及之后的版别在规范库中添加了unittest.mock。假如你运用的是较早版别的Python,你需求装置官方的代码资源库。这儿,你需求从PyPI装置mock:

unittest.mock供给了一个Mock类,它能够模仿你代码库中的实践方针。Mock能够供给极端灵敏精确的数据,它与它的子类能够满意你在测验中遇到的大多数Python mock需求。

unittest.mock库还供给了一个叫做patch()的函数,它能够用Mock方针的实例替换实践的方针。你能够将patch()用作装修器或上下文办理器,然后操控mock方针的运用规模。一旦退出了指定规模,patch()就会运用原始方针替换并铲除你代码中的mock方针。

最终,unittest.mock为mock方针中的惯例问题供给了一些处理方案。

现在,你现已对什么是mock以及你将运用哪些库有了更深的了解。咱们来深入探讨一下unittest.mock供给的功用和办法。

Mock方针

unittest.mock为mock方针供给了一个基类Mock。由于Mock十分灵敏,它的用例实践上并没有多少约束。

首要实例化一个新的Mock实例:

现在能够运用新建的Mock来替换你代码中的方针。你能够经过将其作为参数传递给方针或许从头界说另一个方针来完结这个操作:

当你替换代码中的方针时,Mock有必要模仿的与实践方针相像才干够。不然,Mock无法替换原始方针。

举个比方,假定你正在模仿json库并运用程序调用dumps()办法,那么你的Python mock方针就有必要包含dumps()办法。

接下来,你将了解到Mock是怎样处理这个问题的。

慵懒成员及办法

Mock的实例有必要模仿它所需求替换的方针。为了灵敏的完结这种办法,Mock会在拜访这些特点的时分创立它们。

由于Mock能够动态的创立恣意特点,所以它适用于替换一切方针。

看一个之前的比方,假如你mock一个json库并调用dumps()办法,那么Python mock方针为了让自身的接口能够匹配英文天气预报库里的接口,会创立这个办法。

请留意这两个版别中dumps()的两个重要特征:

1. 与真实的dumps()不同,mock出来的办法不需求任何参数。实践上,它能够接纳你传递给它的任何参数。

2. dumps()办法的回来值相同也是一个Mock方针。Mock能够以递归的办法界说其他的mock方针,以供你在更杂乱的状况下运用。

由于每个mock办法回来的也是一个Mock方针,所以你能够经过多种办法运用mock。

Mock坚持灵敏的一起也供给了满足的信息。接下来,你将会学习到怎样运用mock更好的了解你的代码。

断语检查

Mock实例存储了怎样运用它们的信息。例如,你能够看到你是否调用了一个办法,你怎样调用的这个办法,等等。这儿有两种首要的办法运用到了这些信息。

榜首,你能够断语你的程序运用的方针是你预期的那样:

运用.assert_called()保证你调用了办法,而.assert_called_once()保证你只调用了一次这个办法。

这两个办法都有衍生的其他办法,便于你检查传递给mock办法的参数:

1. .assert_called_with(*args, **kwarge)

2. .assert_called_once_with(*args, **kwarge)

你有必要运用与传递给实践办法相同的参数调用mock的办法,断语才会经过。

json.l我国农林卫视网oads.assert_called_with('{"key": "value"}')抛出了一个AssertionError反常信息,由于你本来期望运用一个方位参数调用loads(),可是实践上你运用了一个关键字参数调用了该办法。json.loads.assert_called_with(s='{"key": "value"}')这样才是正确的。

第飒二,你能够检查Mock的特别特点来了解应用程序怎样运用方针本田翼:

你可运用这些特点编写测验程序,来保证你代码中明末强国梦的方针按预期履行。

现在你能够创立mock猪肚鸡方针并检查其运用的数据。接下来咱们将介绍怎样自界说mock办法来更多的应用于你的测验环境。

办理Mock的回来数据

运用mock的一个原因是在测验期间操控代码的行为。一种办法是指定函数的回来值。咱们来举个比方阐明一下它是怎样作业的。

首要,创立一个名为my_calendar.py的文件,添加一个运用了Python的datetime库的办法is_weekday(),判别今日是否为作业日。最终写一个测验,断语函数依照预期作业。

由于测验的是今日是否为作业日,所以成果取决于运转测验的那天:

假如这个指令运转没有输出成果,那么断语是成功的。不幸的是,假如你在周末运转了这个指令,你将看到一个AssertionError过错。

开端写测验时,保证成果的可预见性是很重要的。你能够在测验过程中运用Mock扫除不确认要素。下面的比方中,你能够mock一个datetime而且经过运用.return龙骨_value为.today()挑选一个friend,读懂Python的Mock方针库(1),崔成国你期望设置的日期。

这个比方中,.today()是一个mock出来的办法。你现现已过mock中的.return_value指定一个特定的日期消除不一致性。这样,当你调用.today()时会回来你指定的日期datetime。

在榜首个测验中,确认了星期二是作业日。第2次测验,确认星期六不是作业日。现在,你运转测验的时分是哪一天不重要了,由于现已能够mockdatetime并操控方针的行为。

进一步阅览:尽管这样经过Mock方针来mock一个datetime的办法是一friend,读懂Python的Mock方针库(1),崔成国个不错的比方,可是现已有一个十分棒的库freezegun能够mock日期datetime了。

在构建测验时,一般由于函数要比简略的毛遂自荐面试单项逻辑更为杂乱碗,你或许会遇到mock的函数回来值不够用的状况。

有时,你或许会屡次调用函数以期能够回来不同的值乃至是抛出反常。你或许运用.side_effect完结这一点。

办理Mock的旁边面影响

你能够经过指定mock的函数的旁边面影响来操控代码的行为。.side_effect界说了当你调用mock的函数是会发作什么。

在my_calendar.py中friend,读懂Python的Mock方针库(1),崔成国添加一个函数来测验这是怎样作业的:

get_holidays()向本地效劳器发起了一个拜访一组假日的恳求。假如效劳器呼应成功,get_holidays()会回来一个字典,不然函数回来None。

你可经过设置requests.get.side_effect来测验get_holidays()是怎样呼应衔接超时的。

关于这个比方,你只能看到my_cale真灵九变ndar.py中的部分相关代码。能够运用unittest库来构建测验用例。

用.assertRaises()验证在设置了旁边面影响的get()函数之后get_holidays()是不是会引发反常。

运转并检查测验成果:

假如你期望愈加动态的加载,能够将.side_effect设置为Mock调用是mock的函数。这个函数会分配side_effect的参数和回来值。

首要,创立.log_request(),它接纳一个URL,运用print()打印输出,然后回来一个mock的呼应。之后,运用.side_effect为.get()设置.log_request(),在调用get_holidays()时会调用这个办法。当你开端运转测验时,能够看到.get()将自己的参数转发给.log_request()然后承受回来值并回来:

很棒,print()句子打印了正确的值。而且get_holidays()也回来了假字典。

.side_effect还能够迭代。迭代的话有必要包含回来值,反常或许两者都有。每次调用mock的办法时,这个迭代会发生下一个值。比方,你能够在Timeout之后重试并回来一个成功的呼应。

榜首次调用get_holidays(),.get()会引发一个Timeout反常。第2次则会回来一个有用的假字典。这些旁边面影响会匹配传递给.side_effect的列表的次序。

你能够直接在Mock方针上设置.return_value和.side_effect。可是Python mock方针期望能灵敏的创立其特点,所以还有很好的办法装备这些以及其他设置。

装备你的Mock

你能够装备Mock来操控方针的某些行为。Mock中可装备的成员包含.side_effect,.return_value以及.name。当你创立或许运用.configure_moc肚脐k()时会装备Mock。

你能够初始化是经过指定某些特点来装备Mock:

尽管能够在Mock实例上设置 .side_effect和.return_value,可是像.name等其他特点只能经过.__init__()或许.configure_mock()来设置。假如你测验在Mock实例上设置.name,你得到成果会不一样:

.name是要运用的方针的公共特点。因而,Mock不答应你以与 .side_effect或.return_value相同的办法来设置这个值。假如你拜访mock.name,将会创立一个.name特点而不是装备mock方针。

你能够运用.configure_mock()装备一个已有的Mock实例:

经过将字典解包到.configure_mock()或Mock.__init__()周涛的女儿,你乃至能够装备Python mock方针的特点。运用Mock装备,能够简化之前的比方:

现在,你能够创立和装备一建Python mock方针了。你还能够运用mock操控你的应用程序的行为。现在,你现已运用mock作为函数的参数或许在与测验中相同的模块中匹配方针。

接下来,你将学习怎样将mock方针替换为其他模块中的动态图出处实践方针。

patch()

unittest.mock为mock方针供给了一种强壮的名为patch()的机制,它能够在给定模块中查找方针并用Mock替换该方针。

一般,运用patch()作为装修器或许上下文办理器来供给一个mock方针方针的规模90010兔子。

patch()作为装修器

假如你要在整个测验函数的继续时间内运用mock方针,能够使雨蝶用patch()作为装修器。

将逻辑代码和测验放入独自的文件从头组织my_calendar.py文件,能够看到其作业原理:

这些函数现在都在自己的文件中,与测验区别开来。接下来,将在tests.py文件中从头创立测验。

到现在为止,你现已在方针各自地点的文件中打了"山公补丁"。山公补丁在运转时将一个方针替换为胆囊切除另一个方针。现在,将运用patch()替换my_calendar.py中的方针:

开始,你在本地规模内创立了Mock方针并对requests打了补丁。现在你需求从tests.py中拜访my_calendar.p中的requests库。

关于这种状况,运用了patch()作为装修器并传递方针方针的途径。方针途径为'my_calendar.requests',它由模块称号和方针组成。

你还为测验函数界说了一个新的参数,patch()运用这个参数将mock方针传递到测验中。这样能够依据断语修正mfriend,读懂Python的Mock方针库(1),崔成国ock或许断语。

你能够履行这个测验模块保证契合预期:

技术细节:patch()会回来一个承继自Mock的MagicMock的实例。MagicMock对你很有协助,由于它运用合理的默认值完结了很多的戏法办法,比方.__len__(), .__str__(), 及 .__iter__()。

运用patch()作为装修器在这个比方中能够正常运转。在某些状况下,运用patch()作为上下文办理器更具有可读性,更有用且更简单。

patch()作为上下文办理器

有时,你会期望运用patch()作为上下文办理器而不是装修器。你更倾向于上下文办理器的原因或许包含:

1. 你只想在测验的一部分规模内mock一个方针

2. 你现已运用了太多的装修器或参数,降低了测验的可读性

想要patch()作为上下文办理器,你能够运用with句子:

当你退出with句子时,patch()将mock方针再替换回原始方针。

现在,你都是mock的完好的方针,可是有时分你或许仅仅期望mock方针的一部分。

为方针的特点打补丁

假定你只期望mock一个方针的办法而不是整个方针。你能够运用patch.object()来完结此操作。

比方,方针办法.test_ge男女相片t_holidays_timeout()实践上仅仅需求mock一个requests.get()并将.side_effect设置为Timeout。

这个比方中,你只mock了get()办法而不是整个requests包,其他的特点仍是与本来相同。

object()选用和patch()相同的装备参数。可是,将方针自身作为榜首个参数传递而不是传递方针的途径。第二个参数是你测验mock的方针方针的特点。你还能够运用object()作为类似于patch()的上下文办理器。

进一步阅览:除了方针和特点,你还能够运用patch.dict()来将patch()作用于字典。

学习怎样运用patch()关于mock其他模块中的方针十分重要。可是,有时分需求mock的方针方针的途径并不显着。

在哪里打补丁

有一个很重要的点是奉告patch()去哪里查找你需求mock的方针,由于假如你挑选了一个过错的方针方位,那么patch()的成果或许出乎你的意料。

假定你在my_calendar.py运用patch()mock函数is_weekday():

首要导入my_calendar.py,然后用Mock替换is_weekday()。很好,运转契合预期。

现在,咱们略微改动一下这个比方,并直接引证函数:

留意:依据你阅览本教程的日期,你从操控台看到的输出或许是Trus或False。重要的是输出与之前的Mock不同。

请留意,即便传递给patch()的方针方位没有更改,调用is_weekday()的成果也不同,这是由于导入函数的办法不同。

from my_calendar import is_weekday意思是将实践函数引进到本地文件规模。因而,即便你稍后运用patch()操作了该函数,之后也会疏忽已有的mock,由于你现已持有对未mock函数的本地引证。

运用patch()的 好的规律是查找这个方针。

在榜首个比方中,mock'my_calendar.is_weekday()'是收效的,由于你是在模块中查找该函数。第二个比方中,你持有对is_weekday(friend,读懂Python的Mock方针库(1),崔成国)的本地引证,由所以在本地规模内找到了函数,所以mock的是本地的函数:

现在,你现已深入领会了patch()的强壮之处。而且知道怎样对方针和特点运用patch()并对为其打补丁。

接下来,你将看到mock方针的一些惯例问题以及unittest.mock供给的处理方案。

英文原文:https://realpython.com/python-mock-library/ 译者:敦伟