Source Code

  1from io import StringIO
  2from unittest.mock import PropertyMock
  3import pytest
  4
  5from mocker_builder import MockerBuilder
  6from test_cases import my_heroes
  7from test_cases.my_heroes import (
  8    Batman,
  9    HobbyHero,
 10    IHero,
 11    JusticeLeague,
 12    OtherHero,
 13    PeakyBlinder,
 14    MyHeroes,
 15    Robin
 16)
 17
 18
 19def print_io_test():
 20    print("Ouieh!!!")
 21
 22
 23class Foo(IHero):
 24    nickname: str = "Bob"
 25
 26    def eating_banana(self) -> str:
 27        return "have no banana"
 28
 29    def wearing_pyjama(self) -> str:
 30        return "have no pyjama"
 31
 32    def just_call_for(self) -> str:
 33        return "Bob Foo"
 34
 35    def just_says(self) -> str:
 36        return "foo foo"
 37
 38
 39class TestMyHeroes(MockerBuilder):
 40    """Main Test Class to implement MockerBuilder features to make your tests"""
 41
 42    @MockerBuilder.initializer
 43    def mocker_builder_setup(self):
 44        # ================== Setting fixtures ===================
 45        self.my_hero = self.add_fixture(
 46            content=lambda: (yield PeakyBlinder(
 47                bananas=12,
 48                pyjamas=7,
 49                nickname="Thomas Shelby"
 50            ))
 51        )
 52        # =================== Setting mocks ======================
 53        self.what_i_do_when_nobody_is_looking = self.patch(
 54            PeakyBlinder,
 55            'what_i_do_when_nobody_is_looking',
 56            return_value=HobbyHero("I just drink wisky")
 57        )
 58        self.get_my_hero_hobby = self.patch(
 59            Robin,
 60            'get_my_hero_hobby',
 61            return_value=HobbyHero("I just watch TV")
 62        )
 63        self.mock_my_heroes_module = self.patch(
 64            target=my_heroes.initialize_other_hero
 65        )
 66        self.mock_my_hero_attribue = self.patch(
 67            target=MyHeroes,
 68            attribute='_my_hero',
 69            mock_configure={
 70                'eating_banana.return_value': "Banana Noooo!",
 71                'just_says.side_effect': ["Nothing to say!"]
 72            }
 73        )
 74        self.mock_other_hero = self.patch(
 75            target=OtherHero,
 76            mock_configure={
 77                'return_value.just_says.return_value': "He feels good!"
 78            }
 79        )
 80        self.my_hero_batman = self.patch(
 81            # XXX or target='main.Batman' to mock the Batman class imported from here.
 82            target=Batman,
 83            mock_configure={
 84                'return_value.nickname': 'Bat Mock',
 85                'return_value.eating_banana.return_value': "doesn't like banana",
 86                'return_value.wearing_pyjama.return_value': "doesn't wear pyjama",
 87                'return_value.just_call_for.return_value': "just calls for Mocker",
 88                'return_value.just_says.return_value': "I'm gonna mock you babe!",
 89            }
 90        )
 91        self.mock_justice_league__init__ = self.patch(
 92            target=JusticeLeague.__init__
 93        )
 94        # ========================================================
 95
 96    def test_io(self):
 97        self.test_print_io = self.patch(
 98            target='sys.stdout',
 99            new_callable=StringIO
100            # spec=StringIO
101        )
102        print_io_test()
103        # assert self.test_print_io.mock.called
104        assert self.test_print_io.mock.getvalue() == 'Ouieh!!!\n'
105
106    def test_another_print_io(self):
107        self.test_print_io = self.patch(
108            target='sys.stdout',
109            new_callable=StringIO
110        )
111        patched_print_io_test = self.patch(
112            target=print_io_test,
113            side_effect=[print("Ooouuiieeh!!")]
114        )
115        print_io_test()
116        assert not self.test_print_io.mock.getvalue() == 'Ouieh!!!\n'
117        assert self.test_print_io.mock.getvalue() == 'Ooouuiieeh!!\n'
118        patched_print_io_test.mock.assert_called()
119
120    def test_robin_becomes_batman(self):
121        self.robin_becomes_batman = self.patch(
122            Robin,
123            new=Batman
124        )
125        robin = Robin()
126        assert robin.nickname == "Little Bastard"
127
128        robin.nickname = "Bat Robinson"
129        assert not self.robin_becomes_batman.mock.nickname == "Bat Robinson"
130        assert self.robin_becomes_batman.mock.nickname == "Big Fat Bat"
131
132        # self.robin_becomes_batman.stop()
133        assert not robin.nickname == "Little Bastard"
134        assert robin.nickname == "Bat Robinson"
135
136    @pytest.mark.asyncio
137    async def test_what_i_do_when_nobody_is_looking(self):
138        # ----------------------- PeakyBlinder ----------------------
139        him = MyHeroes()
140        him.my_hero = PeakyBlinder(
141            my_hobby=HobbyHero(
142                what_i_do="Shot someone"
143            )
144        )
145        peaky_blinder = await him.what_my_hero_does_when_nobody_is_looking()
146
147        assert self.what_i_do_when_nobody_is_looking.mock.called
148        assert not peaky_blinder.what_i_do == "Shot someone"
149        assert peaky_blinder.what_i_do == "I just drink wisky"
150        assert him.does() == "Shot someone"
151        assert not him.does() == "I just drink wisky"
152
153        self.what_i_do_when_nobody_is_looking.set_result(
154            return_value=HobbyHero("Just relax!")
155        )
156        peaky_blinder = await him.what_my_hero_does_when_nobody_is_looking()
157
158        assert not peaky_blinder.what_i_do == "I just drink wisky"
159        assert peaky_blinder.what_i_do == "Just relax!"
160        assert him.does() == "Shot someone"
161        assert not him.does() == "just relax!"
162
163        # ----------------------- Robin ----------------------
164        robs = MyHeroes()
165        robs.my_hero = Robin(
166            my_hobby=HobbyHero(
167                what_i_do="I catch bad guys"
168            )
169        )
170        robin = await robs.what_my_hero_does_when_nobody_is_looking()
171
172        assert not self.get_my_hero_hobby.mock.called
173        assert not robin.what_i_do == "I just watch TV"
174        assert robin.what_i_do == "I catch bad guys"
175
176        # calling does() method calls mocked Robin.get_my_hero_hobby method so get the mocked value
177        assert not robs.does() == "I catch bad guys"
178        assert robs.does() == "I just watch TV"
179        assert self.get_my_hero_hobby.mock.called
180        assert self.get_my_hero_hobby.mock.call_count == 2
181
182        # ================================================================================
183        # -------------------- Robin -> Batman --------------------
184        self.robin_becomes_batman = self.patch(
185            Robin,
186            new=Batman
187        )
188        self.get_my_hero_hobby.stop()
189
190        # Here now we will actually mock Batman.get_my_hero_hobby calling
191        self.get_my_hero_hobby = self.patch(
192            Robin,
193            'get_my_hero_hobby',
194            return_value=HobbyHero("I just watch TV")
195        )
196        robs = MyHeroes()
197        robs.my_hero = Robin(
198            my_hobby=HobbyHero(
199                what_i_do="I catch bad guys"
200            )
201        )
202        robin = await robs.what_my_hero_does_when_nobody_is_looking()
203
204        assert not self.get_my_hero_hobby.mock.called
205        assert not robin.what_i_do == "I just watch TV"
206        assert robin.what_i_do == "I catch bad guys"
207
208        # calling does() method calls mocked Batman.get_my_hero_hobby method so get the mocked value
209        assert robs.does() == "I catch bad guys"
210        assert not robs.does() == "I just watch TV"
211        assert not self.get_my_hero_hobby.mock.called
212        assert self.get_my_hero_hobby.mock.call_count == 0
213
214        # ----------------------------------------------------------------
215        # remember we mocked robin as batman => self.robin_becomes_batman
216        # ----------------------------------------------------------------
217        bats = MyHeroes()
218        bats.my_hero = Batman(
219            my_hobby=HobbyHero(
220                what_i_do="I catch bad guys"
221            )
222        )
223        batman = await robs.what_my_hero_does_when_nobody_is_looking()
224
225        assert not self.get_my_hero_hobby.mock.called
226        assert not batman.what_i_do == "I just watch TV"
227        assert batman.what_i_do == "I catch bad guys"
228        assert bats.does() == "I just watch TV"
229        assert not bats.does() == "I catch bad guys"
230        assert self.get_my_hero_hobby.mock.called
231        assert self.get_my_hero_hobby.mock.call_count == 2
232
233    @pytest.mark.asyncio
234    async def test_heroes_sleeping(self):
235        justce_league = JusticeLeague()
236        assert self.mock_justice_league__init__().called
237
238        async def hero_names():
239            yield Batman().nickname
240            yield Robin().nickname
241        _hero_names = hero_names()
242
243        async for result in justce_league.are_heroes_sleeping():
244            assert result == "=== Heroes are awakened ==="
245
246        self.mock_justice_league__init__.stop()
247        justce_league = JusticeLeague()
248
249        async for result in justce_league.are_heroes_sleeping():
250            _hero_name = await _hero_names.__anext__()
251            print(result, _hero_name)
252            assert result == f"MagicMock=>({_hero_name}): ZZzzzz"
253
254    @pytest.mark.asyncio
255    async def test_call_heroes(self):
256        # Remember that JusticeLeague.__init__ still mocked, so calling JusticeLeague() doesn't
257        # initialize JusticeLeague._heroes attribute.
258
259        justce_league = JusticeLeague()
260        assert await justce_league.call_everybody() == "Uuhmm! Nobody here!"
261
262        with pytest.raises(AttributeError) as ex:
263            justce_league.join_hero(Batman())
264        assert "'JusticeLeague' object has no attribute '_heroes'" == str(ex.value)
265
266        # We just stop mocking JusticeLeague.__init__ to test a different behavior below
267        self.mock_justice_league__init__.stop()
268        del justce_league
269
270        with self.patch(
271            JusticeLeague,
272            '_heroes',
273            create=True,
274            return_value=PropertyMock(spec=list, return_value=[])
275        ):
276
277            justce_league = JusticeLeague()
278            justce_league.join_hero(Batman())
279            # my_heroes.Batman() still mocked
280            justce_league.join_hero(my_heroes.Batman())
281
282            assert await justce_league.call_everybody() == [
283                ('Batman', 'Come on', 'Big Fat Bat'),
284                ('MagicMock', 'Come on', 'Bat Mock')
285            ]
286
287    def test_mock_my_heroes_class(self):
288        mock_my_heroes_class = self.patch(
289            target=MyHeroes
290        )
291        my_heroes.who_is_the_best_hero()
292        assert mock_my_heroes_class().called
293
294    def test_mock_my_heroes_module(self):
295        self.mock_my_heroes_module.stop()
296        my_heroes.who_is_the_best_hero()
297        assert not self.mock_my_heroes_module().called
298
299        self.mock_my_heroes_module.start()
300        my_heroes.who_is_the_best_hero()
301        assert self.mock_my_heroes_module().called
302
303    def test_mock_my_hero_attribute(self):
304        assert self.mock_my_hero_attribue().eating_banana() == "Banana Noooo!"
305        assert self.mock_my_hero_attribue.mock.just_says() == "Nothing to say!"
306
307    def test_mock_my_class(self):
308        response = my_heroes.asks_what_other_hero_have_to_say_about_been_hero()
309        assert response == "He feels good!"
310
311    def test_my_hero_batman(self):
312        my_heroes.who_is_my_hero(Batman())
313
314        testing = MyHeroes()
315        testing.my_hero = my_heroes.Batman()
316        testing.who_is_my_hero()
317
318        assert self.my_hero_batman.mock.return_value.nickname == 'Bat Mock'
319        assert testing.my_hero.nickname == 'Bat Mock'
320
321    def test_mock_justice_league__init__(self):
322        justce_league = JusticeLeague()
323        assert justce_league.show_heroes() == "Opss! No heroes over here!"
324        assert justce_league.what_heroes_does() == "Eita! Heroes are doing nothing!"
325
326        self.mock_justice_league__init__.stop()
327
328        justce_league = JusticeLeague()
329        # my_heroes.Batman() is mocked
330        justce_league.join_hero(my_heroes.Batman())
331        justce_league.join_hero(Robin())
332
333        mock_test_io = self.patch(
334            target='sys.stdout',
335            new_callable=StringIO
336        )
337        justce_league.show_heroes()
338        expected = """MagicMock just calls for Mocker
339Robin just calls for Little Bastard\n"""
340        assert mock_test_io().getvalue() == expected
341
342        justce_league.what_heroes_does()
343        expected += """===========================
344Bat Mock
345doesn't like banana
346doesn't wear pyjama
347I'm gonna mock you babe!
348===========================
349Little Bastard
350is eating 1 banana(s)
351is wearing 4 pyjama(s)
352I'm gonna have a pint!\n"""
353        assert mock_test_io().getvalue() == expected
354
355        mock_test_io.stop()
356        self.mock_justice_league__init__.start()
357
358        justce_league = JusticeLeague()
359        assert justce_league.show_heroes() == "Opss! No heroes over here!"
360        assert justce_league.what_heroes_does() == "Eita! Heroes are doing nothing!"
361
362    def test_mock_ugly_hero(self):
363
364        assert my_heroes.UGLY_HERO == 'Me'
365
366        mock_ugly_hero = self.patch(
367            target=my_heroes,
368            attribute='UGLY_HERO',
369            mock_configure={
370                'third': 'You',
371                'who_is_the_most_ugly.return_value': 'Me again',
372            },
373            first='Batman',
374            second='Robin',
375            call_me_a_hero=lambda: PeakyBlinder().nickname
376        )
377        mock_ugly_hero.configure_mock(
378            fourth='Me',
379            **{
380                'who_is_my_hero.return_value': Batman().nickname,
381                'who_is_the_most_beautiful.side_effect': ValueError("There isn't any beautiful hero")
382            }
383        )
384
385        assert mock_ugly_hero().first == 'Batman'
386        assert mock_ugly_hero().second == 'Robin'
387        assert mock_ugly_hero().third == 'You'
388        assert mock_ugly_hero().fourth == 'Me'
389        assert mock_ugly_hero().who_is_the_most_ugly() == 'Me again'
390        assert mock_ugly_hero().call_me_a_hero() == "Bart Burp"
391        assert mock_ugly_hero().who_is_my_hero() == "Big Fat Bat"
392
393        with pytest.raises(ValueError) as ex:
394            mock_ugly_hero().who_is_the_most_beautiful()
395        assert "There isn't any beautiful hero" == str(ex.value)
396
397    def test_how_can_we_call_for_heores(self):
398        self.mock_justice_league__init__.stop()
399        self.my_hero_batman.stop()
400
401        justce_league = JusticeLeague()
402        # my_heroes.Batman() is mocked but was stopped
403        justce_league.join_hero(my_heroes.Batman())
404        justce_league.join_hero(Robin())
405        assert justce_league.how_can_we_call_for_heores() == [
406            ("Batman", "just calls for Big Fat Bat"),
407            ("Robin", "just calls for Little Bastard")
408        ]
409        self.mock_justice_league__init__.start()
410        justce_league = JusticeLeague()
411        assert self.mock_justice_league__init__().called
412        assert justce_league.how_can_we_call_for_heores() == "Opss! No heroes over here to call for!"
413
414        self.my_hero_batman.start()
415        self.mock_justice_league__init__.stop()
416
417        justce_league = JusticeLeague()
418        # my_heroes.Batman() is mocked and was started again
419        justce_league.join_hero(my_heroes.Batman())
420        justce_league.join_hero(Robin())
421        assert justce_league.how_can_we_call_for_heores() == [
422            ("MagicMock", "just calls for Mocker"),
423            ("Robin", "just calls for Little Bastard")
424        ]
425        assert self.my_hero_batman.mock.called
426
427    def test_my_hero_robin(self):
428        my_hero_robin = self.patch(
429            target=Robin(),  # XXX we can mock from object instance! Ouieh!
430            return_value=PropertyMock(
431                nickname='Bastard Mock',
432                eating_banana=lambda: "eat a lot of bananas",
433                wearing_pyjama=lambda: "likes to be naked",
434                just_call_for=lambda: "Little Mocker",
435                just_says=lambda: "Mock me baby!"
436            )
437        )
438
439        my_heroes.who_is_my_hero(Robin())
440        testing = MyHeroes()
441        testing.my_hero = my_heroes.Robin()
442        testing.who_is_my_hero()
443
444        assert my_hero_robin.mock.called
445        assert my_hero_robin.mock.return_value.nickname == 'Bastard Mock'
446        assert my_hero_robin.mock.return_value.eating_banana() == "eat a lot of bananas"
447        assert my_hero_robin.mock.return_value.wearing_pyjama() == "likes to be naked"
448        assert my_hero_robin.mock.return_value.just_call_for() == "Little Mocker"
449        assert my_hero_robin.mock.return_value.just_says() == "Mock me baby!"
450
451    def test_set_result_return_value(self):
452        my_hero_robin = self.patch(
453            target=Robin,
454            return_value=Foo()
455        )
456
457        print("--------------------------------------------------------------------------")
458        print("Who is my hero:")
459        print("--------------------------------------------------------------------------")
460        my_heroes.who_is_my_hero(Robin())
461
462        testing = MyHeroes()
463        testing.my_hero = my_heroes.Robin()
464        print("--------------------------------------------------------------------------")
465        print("Who is my mocked hero with return_value = Foo():")
466        print("--------------------------------------------------------------------------")
467        testing.who_is_my_hero()
468
469        assert my_hero_robin.mock.called
470        assert isinstance(my_hero_robin.mock.return_value, Foo)
471
472        print("--------------------------------------------------------------------------")
473        print("Setting mock result return_value=PeakyBlinder()")
474        print("--------------------------------------------------------------------------")
475        my_hero_robin.set_result(
476            return_value=PeakyBlinder()
477        )
478        assert not isinstance(my_hero_robin.mock.return_value, Foo)
479        assert isinstance(my_hero_robin.mock.return_value, PeakyBlinder)
480
481        testing = MyHeroes()
482        testing.my_hero = my_heroes.Robin()
483        print("--------------------------------------------------------------------------")
484        print("Who is my mocked hero with return_value = PeakyBlinder():")
485        print("--------------------------------------------------------------------------")
486        testing.who_is_my_hero()
487
488    def test_set_result_side_effect(self):
489        my_hero_robin = self.patch(
490            target=PeakyBlinder,
491            side_effect=lambda: Foo()
492        )
493
494        print("--------------------------------------------------------------------------")
495        print("Who is my hero:")
496        print("--------------------------------------------------------------------------")
497        my_heroes.who_is_my_hero(PeakyBlinder())
498
499        testing = MyHeroes()
500        testing.my_hero = my_heroes.PeakyBlinder()
501        print("--------------------------------------------------------------------------")
502        print("Who is my mocked hero with side_effect = Foo():")
503        print("--------------------------------------------------------------------------")
504        testing.who_is_my_hero()
505
506        assert my_hero_robin.mock.called
507        assert isinstance(testing.my_hero, Foo)
508
509        print("--------------------------------------------------------------------------")
510        print("""Setting mock result side_effect=[
511    OtherHero(),
512    TypeError('Ops! No hero like that!')
513]""")
514        print("--------------------------------------------------------------------------")
515        my_hero_robin.set_result(
516            side_effect=[OtherHero(), TypeError("Ops! No hero like that!")]
517        )
518        testing.my_hero = my_heroes.PeakyBlinder()
519
520        assert not isinstance(testing.my_hero, Foo)
521        assert isinstance(testing.my_hero, OtherHero)
522
523        print("--------------------------------------------------------------------------")
524        print("Who is my mocked hero with side_effect = OtherHero():")
525        print("--------------------------------------------------------------------------")
526        testing.who_is_my_hero()
527
528        print("--------------------------------------------------------------------------")
529        print("Testing side_effect = TypeError('Ops! No hero like that!')")
530        print("--------------------------------------------------------------------------")
531        with pytest.raises(TypeError) as ex:
532            testing.my_hero = my_heroes.PeakyBlinder()
533            testing.who_is_my_hero()
534        assert "Ops! No hero like that!" == str(ex.value)
535
536    def test_create_my_heroes_method_runtime(self):
537        runtime_method = self.patch(
538            target=MyHeroes,
539            method='runtime_method',
540            create=True,
541            # return_value="Ouieh! I'm runtime method running...", # Also works
542            # mock_configure={
543            #     'return_value': "Ouieh! I'm runtime created method running..." # Also works
544            # },
545        )
546        runtime_method.configure_mock(
547            return_value="Ouieh! I'm runtime created method running..."
548        )
549        _my_heroes = MyHeroes()
550        _my_heroes.run_created_runtime_method()
551        assert runtime_method.mock.called