本文转载自微信公众号《AirPython》,作者郭兴安。转载本文请联系AirPython公众号.1.前言在微服务架构下,由于各种服务的开发进度不一致,联调工作往往存在不确定性,进而导致项目延期。在实际工作中,为了保证项目的进度,我们经常需要针对一些未完成的模块和不稳定的模块,使用Mock的方式对开发的模块进行验证。本文将介绍在Python中实现Mock的几种常用方式,将其替换为虚拟对象以测试测试方法。因此,这个虚拟对象是一个Mock对象,Mock对象是调试时真实对象的替代品。其优势包括:前后端并行开发模拟不可访问资源系统隔离,避免脏数据干扰测试结果3.1mock在Python3.3中使用mocks之前,需要先安装依赖#Installmockdependenciespip3installmock项目地址:https://github.com/testing-cabal/mock假设Product类中有2个方法get_product_status_by_idbuy_product,其中get_product_status_by_id方法还没有实现;buy_product方法依赖于get_product_status_by_id方法的返回值#product_impl.pyclassProduct(object):def__init__(self):passdefget_product_status_by_id(self,product通过id获取产品):"mock):return:"""#Buy商家查询数据库的逻辑passdefbuy_product(self,product_id):"""购买产品(真逻辑):return:"""#ProductInformation#{"id":1,"name":"apple","num":23}product=self.get_product_status_by_id(product_id)ifproduct.get("num")>=1:result={"status":0,"msg":"购买成功!"}else:result={"status":1,"msg":"购买失败,库存不足!"}returnresultMock的步骤如下:引入mock中的patch方法作为测试方法的装饰器,Mockget_product_status_by_id方法,方法参数为Mock对象在测试方法中,设置一个返回值调用为mock对象并断言frommockimportpatchfrommock_.product_implimportProduct@patch('mock_.product_impl.Product.get_product_status_by_id')deftest_succuse(mock_get_product_status_by_id):#Mock方法,指定一个返回值mock_get_product_status_by_id.return_value={"id":1,"name":"apple","num":23}product=Product()assertproduct.buy_product(1).get("status")==0需要注意的是,mock该方法时,必须指定该方法的完整路径。使用@patch.object也可以完成Mocking,不同的是@patch.object包含2个参数,第一个参数是方法所在的类;第二个参数是方法名frommockimportpatchfrommock_.product_implimportProduct#Mock一个方法#@patch.object:对象,方法名@patch。对象(产品,'get_product_status_by_id')deftest_sucuse(mock_get_product_status_by_id):#Mock方法,指定一个返回值mock_get_product_status_by_id.return_value={"id":1,"name":"apple","num":23}product=Product()assertproduct.buy_product(1).get("status")==03.2unittest.mock在Python3.3之后,mock已经作为标准库内置到unittest中。以3.1的场景为例,使用unittest编写测试用例Mock的步骤如下:在unittest框架中导入mock文件,实例化Product对象mock。Mock(return_value=*)方法对get_product_status_by_id方法进行Mock调用并断言importunittestfromunittestimportmockfromunittest_mock.product_implimportProductclassTestProduct(unittest.TestCase):deftest_success(self):#Successresultmock_success_value={"id":1,"name":"apple",num":23}product=Product()product.get_product_status_by_id=mock.Mock(return_value=mock_success_value)#调用实际函数assertproduct.buy_product(1).get("status")==0if__name__=="__main__":unittest.main()3.3pytest.mockpytest相比unittest,由于强大的插件支持,可能会有更大的用户群!如果项目本身使用的框架是pytest,Mock推荐使用插件pytest-模拟#pytest依赖pip3installpytestMock,步骤如下:使用pytest编写测试方法,参数为mocker实例化Product对象使用mocker.patch()方法Mockget_product_status_by_id方法,并设置返回值调用并断言importpytestfrompytest_mock_。product_implimportProductdeftest_buy_product_success(mocker):"""购买成功Mock:parammocker::return:"""#实例化一个产品对象product=Product()#MockmockProduct={"id":1,"name中方法的返回值":"apple","num":23}#MockMethod#注意:需要指定方法的完整路径#mocker.patch第一个参数必须是模拟对象的具体路径,使用第二个参数指定返回值product.get_product_status_by_id=mocker.patch("product_impl.Product.get_product_status_by_id",return_value=mock_value)#调用购买产品的方法result=product.buy_product(1)assertresult.get("status")==0需要注意的是mocker.patch方法第一个参数必须是Mock对象的完整路径4.最后,文章讲解了Python中常见的Mock解决方案。在实际应用中,建议根据项目实际情况选择型号。
