Package: mocker-builder
Mocker BuilderTesting tools for mocking and patching based on pytest_mock mocker features but with improvements.Installation$pipinstallmocker-builderInitializerTo start using mucker-builder features just create your Test class, inherit fromMockerBuilderclass,
implement the required abstract method mocker_builder_setup decorating it with the@MockerBuilder.initializerdecorator and start building your mocks and fixtures, adding mocks from your test_... methods,
but you must declare themocker_builder_setupmethod and decorate it with the@MockerBuilder.initializerdecorator to be able to useMockerBuilderfeatures....defprint_io_test():print("Ouieh!!!")classTestMyHeroes(MockerBuilder):@MockerBuilder.initializerdefmocker_builder_setup(self):pass...deftest_io(self):print_test_io=self.patch(target='sys.stdout',new_callable=StringIO)print_io_test()assertprint_test_io.mock.getvalue()=='Ouieh!!!\n'If you wanna use print_test_io all over your tests just patch it intomocker_builder_setup:...defprint_io_test():print("Ouieh!!!")classTestMyHeroes(MockerBuilder):@MockerBuilder.initializerdefmocker_builder_setup(self):self.print_test_io=self.patch(target='sys.stdout',new_callable=StringIO)...deftest_print_io(self):print_io_test()assertself.print_test_io.mock.getvalue()=='Ouieh!!!\n'deftest_another_print_io(self):patched_print_io_test=self.patch('__main__.print_io_test',side_effect=[print("Ooouuiieeh!!")])print_io_test()assertnotself.print_test_io.mock.getvalue()=='Ouieh!!!\n'assertself.print_test_io.mock.getvalue()=='Ooouuiieeh!!!\n'The self.patch TMocker.PatchType propertiesTheself.patchmethod creates a new patch/mock object. It is a patch/mock because by doing:my_patched_thing=self.patch(...)my_patched_thinghas some properties of a mock.patch object, like start, stop and set_result.
To get access to the patched mock we can just access themockpatched attribute:assertmy_patched_thing.mock.calledOrassertmy_patched_thing().calledBoth ways return an MagicMock or an AsyncMock (Not yet really but still working on this feature)
if the tested method is async.Setting result after already been patchedFor a complete exemple flow just have a look bellow:fromioimportStringIOfromunittest.mockimportPropertyMockimportpytestfrommocker_builderimportMockerBuilderfrommy_heroesimportthemfrommy_heroes.themimport(Batman,HobbyHero,IHero,JusticeLeague,OtherHero,PeakyBlinder,MyHeroes,Robin)defprint_io_test():print("Ouieh!!!")classFoo(IHero):nickname:str="Bob"defeating_banana(self)->str:return"have no banana"defwearing_pyjama(self)->str:return"have no pyjama"defjust_call_for(self)->str:return"Bob Foo"defjust_says(self)->str:return"foo foo"classTestMyHeroes(MockerBuilder):@MockerBuilder.initializerdefmocker_builder_setup(self):# ================== Setting fixtures ===================# TODO We will work on this feature to implement a real fixtureself.my_hero=self.add_fixture(content=PeakyBlinder(bananas=12,pyjamas=7,nickname="Thomas Shelby"))# =================== Setting mocks ======================self.what_i_do_when_nobody_is_looking=self.patch(PeakyBlinder,'what_i_do_when_nobody_is_looking',return_value=HobbyHero("I just drink wisky"))self.get_my_hero_hobby=self.patch(Robin,'get_my_hero_hobby',return_value=HobbyHero("I just watch TV"))self.mock_my_heroes_module=self.patch(target=them.initialize_other_hero)self.mock_my_hero_attribue=self.patch(target=MyHeroes,attribute='_my_hero',mock_configure={'eating_banana.return_value':"Banana Noooo!",'just_says.side_effect':["Nothing to say!"]})self.mock_other_hero=self.patch(target=OtherHero,mock_configure={'return_value.just_says.return_value':"He feels good!"})self.my_hero_batman=self.patch(# XXX or target='main.Batman' to mock the Batman class imported from here.target=Batman,mock_configure={'return_value.nickname':'Bat Mock','return_value.eating_banana.return_value':"doesn't like banana",'return_value.wearing_pyjama.return_value':"doesn't wear pyjama",'return_value.just_call_for.return_value':"just calls for Mocker",'return_value.just_says.return_value':"I'm gonna mock you babe!",})self.mock_justice_league__init__=self.patch(target=JusticeLeague.__init__)# ========================================================@pytest.mark.asyncioasyncdeftest_what_i_do_when_nobody_is_looking(self):# ----------------------- PeakyBlinder ----------------------him=MyHeroes()him.my_hero=PeakyBlinder(my_hobby=HobbyHero(what_i_do="Shot someone"))peaky_blinder=awaithim.what_my_hero_does_when_nobody_is_looking()assertself.what_i_do_when_nobody_is_looking.mock.calledassertnotpeaky_blinder.what_i_do=="Shot someone"assertpeaky_blinder.what_i_do=="I just drink wisky"asserthim.does()=="Shot someone"assertnothim.does()=="I just drink wisky"self.what_i_do_when_nobody_is_looking.set_result(return_value=HobbyHero("Just relax!"))peaky_blinder=awaithim.what_my_hero_does_when_nobody_is_looking()assertnotpeaky_blinder.what_i_do=="I just drink wisky"assertpeaky_blinder.what_i_do=="Just relax!"asserthim.does()=="Shot someone"assertnothim.does()=="just relax!"# ----------------------- Robin ----------------------robs=MyHeroes()robs.my_hero=Robin(my_hobby=HobbyHero(what_i_do="I catch bad guys"))robin=awaitrobs.what_my_hero_does_when_nobody_is_looking()assertnotself.get_my_hero_hobby.mock.calledassertnotrobin.what_i_do=="I just watch TV"assertrobin.what_i_do=="I catch bad guys"# calling does() method calls mocked Robin.get_my_hero_hobby method so get the mocked valueassertnotrobs.does()=="I catch bad guys"assertrobs.does()=="I just watch TV"assertself.get_my_hero_hobby.mock.calledassertself.get_my_hero_hobby.mock.call_count==2# ================================================================================# -------------------- Robin -> Batman --------------------self.robin_becomes_batman=self.patch(Robin,new=Batman)self.get_my_hero_hobby.stop()# Here now we will actually mock Batman.get_my_hero_hobby callingself.get_my_hero_hobby=self.patch(Robin,'get_my_hero_hobby',return_value=HobbyHero("I just watch TV"))robs=MyHeroes()robs.my_hero=Robin(my_hobby=HobbyHero(what_i_do="I catch bad guys"))robin=awaitrobs.what_my_hero_does_when_nobody_is_looking()assertnotself.get_my_hero_hobby.mock.calledassertnotrobin.what_i_do=="I just watch TV"assertrobin.what_i_do=="I catch bad guys"# calling does() method calls mocked Batman.get_my_hero_hobby method so get the mocked valueassertrobs.does()=="I catch bad guys"assertnotrobs.does()=="I just watch TV"assertnotself.get_my_hero_hobby.mock.calledassertself.get_my_hero_hobby.mock.call_count==0# ----------------------------------------------------------------# remember we mocked robin as batman => self.robin_becomes_batman# ----------------------------------------------------------------bats=MyHeroes()bats.my_hero=Batman(my_hobby=HobbyHero(what_i_do="I catch bad guys"))batman=awaitrobs.what_my_hero_does_when_nobody_is_looking()assertnotself.get_my_hero_hobby.mock.calledassertnotbatman.what_i_do=="I just watch TV"assertbatman.what_i_do=="I catch bad guys"assertbats.does()=="I just watch TV"assertnotbats.does()=="I catch bad guys"assertself.get_my_hero_hobby.mock.calledassertself.get_my_hero_hobby.mock.call_count==2deftest_io(self):self.mock_test_io=self.patch(target='sys.stdout',new_callable=StringIO)print_io_test()assertself.mock_test_io().getvalue()=='Ouieh!!!\n'@pytest.mark.asyncioasyncdeftest_heroes_sleeping(self):justce_league=JusticeLeague()assertself.mock_justice_league__init__().calledasyncdefhero_names():yieldBatman().nicknameyieldRobin().nickname_hero_names=hero_names()asyncforresultinjustce_league.are_heroes_sleeping():assertresult=="=== Heroes are awakened ==="self.mock_justice_league__init__.stop()justce_league=JusticeLeague()asyncforresultinjustce_league.are_heroes_sleeping():_hero_name=await_hero_names.__anext__()print(result,_hero_name)assertresult==f"MagicMock=>({_hero_name}): ZZzzzz"@pytest.mark.asyncioasyncdeftest_call_heroes(self):# Remember that JusticeLeague.__init__ still mocked, so calling JusticeLeague() doesn't# initialize JusticeLeague._heroes attribute.justce_league=JusticeLeague()assertawaitjustce_league.call_everybody()=="Uuhmm! Nobody here!"withpytest.raises(AttributeError)asex:justce_league.join_hero(Batman())assert"'JusticeLeague' object has no attribute '_heroes'"==str(ex.value)# We just stop mocking JusticeLeague.__init__ to test a different behavior belowself.mock_justice_league__init__.stop()deljustce_leaguewithself.patch(JusticeLeague,'_heroes',create=True,return_value=PropertyMock(spec=list,return_value=[])):justce_league=JusticeLeague()justce_league.join_hero(Batman())# my_heroes.Batman() still mockedjustce_league.join_hero(them.Batman())assertawaitjustce_league.call_everybody()==[('Batman','Come on','Big Fat Bat'),('MagicMock','Come on','Bat Mock')]deftest_mock_my_heroes_class(self):mock_my_heroes_class=self.patch(target=MyHeroes)them.who_is_the_best_hero()assertmock_my_heroes_class().calleddeftest_mock_my_heroes_module(self):self.mock_my_heroes_module.stop()them.who_is_the_best_hero()assertnotself.mock_my_heroes_module().calledself.mock_my_heroes_module.start()them.who_is_the_best_hero()assertself.mock_my_heroes_module().calleddeftest_mock_my_hero_attribute(self):assertself.mock_my_hero_attribue().eating_banana()=="Banana Noooo!"assertself.mock_my_hero_attribue.mock.just_says()=="Nothing to say!"deftest_mock_my_class(self):response=them.asks_what_other_hero_have_to_say_about_been_hero()assertresponse=="He feels good!"deftest_my_hero_batman(self):them.who_is_my_hero(Batman())testing=MyHeroes()testing.my_hero=them.Batman()testing.who_is_my_hero()assertself.my_hero_batman.mock.return_value.nickname=='Bat Mock'asserttesting.my_hero.nickname=='Bat Mock'deftest_mock_justice_league__init__(self):justce_league=JusticeLeague()assertjustce_league.show_heroes()=="Opss! No heroes over here!"assertjustce_league.what_heroes_does()=="Eita! Heroes are doing nothing!"self.mock_justice_league__init__.stop()justce_league=JusticeLeague()# my_heroes.Batman() is mockedjustce_league.join_hero(them.Batman())justce_league.join_hero(Robin())mock_test_io=self.patch(target='sys.stdout',new_callable=StringIO)justce_league.show_heroes()expected="""MagicMock just calls for MockerRobin just calls for Little Bastard\n"""assertmock_test_io().getvalue()==expectedjustce_league.what_heroes_does()expected+="""===========================Bat Mockdoesn't like bananadoesn't wear pyjamaI'm gonna mock you babe!===========================Little Bastardis eating 1 banana(s)is wearing 4 pyjama(s)I'm gonna have a pint!\n"""assertmock_test_io().getvalue()==expectedmock_test_io.stop()self.mock_justice_league__init__.start()justce_league=JusticeLeague()assertjustce_league.show_heroes()=="Opss! No heroes over here!"assertjustce_league.what_heroes_does()=="Eita! Heroes are doing nothing!"deftest_mock_ugly_hero(self):assertthem.UGLY_HERO=='Me'mock_ugly_hero=self.patch(target=them,attribute='UGLY_HERO',mock_configure={'third':'You','who_is_the_most_ugly.return_value':'Me again'},first='Batman',second='Robin',call_me_a_hero=lambda:PeakyBlinder().nickname)mock_ugly_hero().configure_mock(fourth='Me',**{'who_is_my_hero.return_value':Batman().nickname,'who_is_the_most_beautiful.side_effect':ValueError("There isn't any beautiful hero")})assertmock_ugly_hero().first=='Batman'assertmock_ugly_hero().second=='Robin'assertmock_ugly_hero().third=='You'assertmock_ugly_hero().fourth=='Me'assertmock_ugly_hero().who_is_the_most_ugly()=='Me again'assertmock_ugly_hero().call_me_a_hero()=="Bart Burp"assertmock_ugly_hero().who_is_my_hero()=="Big Fat Bat"withpytest.raises(ValueError)asex:mock_ugly_hero().who_is_the_most_beautiful()assert"There isn't any beautiful hero"==str(ex.value)deftest_how_can_we_call_for_heores(self):self.mock_justice_league__init__.stop()self.my_hero_batman.stop()justce_league=JusticeLeague()# my_heroes.Batman() is mocked but was stoppedjustce_league.join_hero(them.Batman())justce_league.join_hero(Robin())assertjustce_league.how_can_we_call_for_heores()==[("Batman","just calls for Big Fat Bat"),("Robin","just calls for Little Bastard")]self.mock_justice_league__init__.start()justce_league=JusticeLeague()assertself.mock_justice_league__init__().calledassertjustce_league.how_can_we_call_for_heores()=="Opss! No heroes over here to call for!"self.my_hero_batman.start()self.mock_justice_league__init__.stop()justce_league=JusticeLeague()# my_heroes.Batman() is mocked and was started againjustce_league.join_hero(them.Batman())justce_league.join_hero(Robin())assertjustce_league.how_can_we_call_for_heores()==[("MagicMock","just calls for Mocker"),("Robin","just calls for Little Bastard")]assertself.my_hero_batman.mock.calleddeftest_my_hero_robin(self):my_hero_robin=self.patch(target=Robin(),# XXX we can mock from object instance! Ouieh!return_value=PropertyMock(nickname='Bastard Mock',eating_banana=lambda:"eat a lot of bananas",wearing_pyjama=lambda:"likes to be naked",just_call_for=lambda:"Little Mocker",just_says=lambda:"Mock me baby!"))them.who_is_my_hero(Robin())testing=MyHeroes()testing.my_hero=them.Robin()testing.who_is_my_hero()assertmy_hero_robin.mock.calledassertmy_hero_robin.mock.return_value.nickname=='Bastard Mock'assertmy_hero_robin.mock.return_value.eating_banana()=="eat a lot of bananas"assertmy_hero_robin.mock.return_value.wearing_pyjama()=="likes to be naked"assertmy_hero_robin.mock.return_value.just_call_for()=="Little Mocker"assertmy_hero_robin.mock.return_value.just_says()=="Mock me baby!"deftest_set_result_return_value(self):my_hero_robin=self.patch(target=Robin,return_value=Foo())print("--------------------------------------------------------------------------")print("Who is my hero:")print("--------------------------------------------------------------------------")them.who_is_my_hero(Robin())testing=MyHeroes()testing.my_hero=them.Robin()print("--------------------------------------------------------------------------")print("Who is my mocked hero with return_value = Foo():")print("--------------------------------------------------------------------------")testing.who_is_my_hero()assertmy_hero_robin.mock.calledassertisinstance(my_hero_robin.mock.return_value,Foo)print("--------------------------------------------------------------------------")print("Setting mock result return_value=PeakyBlinder()")print("--------------------------------------------------------------------------")my_hero_robin.set_result(return_value=PeakyBlinder())assertnotisinstance(my_hero_robin.mock.return_value,Foo)assertisinstance(my_hero_robin.mock.return_value,PeakyBlinder)testing=MyHeroes()testing.my_hero=them.Robin()print("--------------------------------------------------------------------------")print("Who is my mocked hero with return_value = PeakyBlinder():")print("--------------------------------------------------------------------------")testing.who_is_my_hero()deftest_set_result_side_effect(self):my_hero_robin=self.patch(target=PeakyBlinder,side_effect=lambda:Foo())print("--------------------------------------------------------------------------")print("Who is my hero:")print("--------------------------------------------------------------------------")them.who_is_my_hero(PeakyBlinder())testing=MyHeroes()testing.my_hero=them.PeakyBlinder()print("--------------------------------------------------------------------------")print("Who is my mocked hero with side_effect = Foo():")print("--------------------------------------------------------------------------")testing.who_is_my_hero()assertmy_hero_robin.mock.calledassertisinstance(testing.my_hero,Foo)print("--------------------------------------------------------------------------")print("""Setting mock result side_effect=[OtherHero(),TypeError('Ops! No hero like that!')]""")print("--------------------------------------------------------------------------")my_hero_robin.set_result(side_effect=[OtherHero(),TypeError("Ops! No hero like that!")])testing.my_hero=them.PeakyBlinder()assertnotisinstance(testing.my_hero,Foo)assertisinstance(testing.my_hero,OtherHero)print("--------------------------------------------------------------------------")print("Who is my mocked hero with side_effect = OtherHero():")print("--------------------------------------------------------------------------")testing.who_is_my_hero()print("--------------------------------------------------------------------------")print("Testing side_effect = TypeError('Ops! No hero like that!')")print("--------------------------------------------------------------------------")withpytest.raises(TypeError)asex:testing.my_hero=them.PeakyBlinder()testing.who_is_my_hero()assert"Ops! No hero like that!"==str(ex.value)