Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock parent class __init__ method

I am trying to write some unittests on a class which is derived from another, but I have some difficulties to mock the parent class init method, which afaik you cannot, so I am looking for suggestion.

Here an example of how are my classes

Imported.py

class Imported():
    def __init__(self, a="I am Imported"):
        print("a:{}".format(a))

Parent.py

from Imported import Imported

class Parent(object):

    parent_list = ["PARENT"]

    def __init__(self, a="I am Parent"):
        imported = Imported(a)

Derived.py

from Parent import Parent

class Derived(Parent):

    Parent.parent_list.append("DERIVED")

In my unittests I want to verify that Parent.parent_list == ["PARENT", "DERIVED"] when I instantiate an object from the Derived class, Derived().

Both of this solution doesn't work

test_Derived.py

import unittest
from mock import patch

from Derived import Derived


class test_Derived(unittest.TestCase):

    @patch("Derived.Parent.__init__")
    def test_init_001(self, mock_parent_init):
        a = Derived("I am Derived")
        mock_parent_init.assert_called_with("I am Derived")
        self.assertEquals(a.parent_list, ["PARENT", "DERIVED"])

    @patch("Derived.Imported.Imported")
    def test_init_002(self, mock_parent_init):
        a = Derived("I am Derived")
        mock_parent_init.assert_called_with("I am Derived")
        self.assertEquals(a.parent_list, ["PARENT", "DERIVED"])

test_init_001 fails with

TypeError: __init__() should return None, not 'MagicMock'

test_init_002 fails with

ImportError: No module named Parent.Imported

Any suggestion?

like image 333
user2944566 Avatar asked Sep 02 '15 09:09

user2944566


People also ask

What is side_ effect in mock Python?

side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT , the return value of this function is used as the return value.

What is the difference between mock and MagicMock?

With Mock you can mock magic methods but you have to define them. MagicMock has "default implementations of most of the magic methods.". If you don't need to test any magic methods, Mock is adequate and doesn't bring a lot of extraneous things into your tests.

How does mock work Python?

mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.


Video Answer


1 Answers

For the first solution, change the return value of the __init__ method to None.

@patch("Derived.Parent.__init__")
def test_init_001(self, mock_parent_init):
    mock_parent_init.return_value = None  # <---
    a = Derived("I am Derived")
    mock_parent_init.assert_called_with("I am Derived")
    self.assertEquals(a.parent_list, ["PARENT", "DERIVED"])

For the second solution, patch Parent.Imported:

@patch("Parent.Imported")  # <---
def test_init_002(self, mock_parent_init):
    a = Derived("I am Derived")
    mock_parent_init.assert_called_with("I am Derived")
    self.assertEquals(a.parent_list, ["PARENT", "DERIVED"])
like image 163
falsetru Avatar answered Sep 27 '22 11:09

falsetru