0

I've been banging my head against the wall on a small mockup like this:

Here's the tree:

src
├── __init__.py
├── file_a.py
├── file_b.py


test
├── test_a.py

In file_a:

class qaz(object):
    def __init__(self):
        print("\n\nin qaz")

    def exec_bar(self):
        bar_inst = bar()
        bar_inst.execute("a", "b")

In file_b:

class bar(object):
    def __init__(self, a, b):
        print("\n\nin bar")

    def execute(self, c, d):
        print("\n\nin bar -> execute")

So, I want to mock bar so that I can test a without any issues.

In test_a:

from unittest.mock import patch, MagicMock
from src.file_a import qaz
from src.file_b import bar

class BarTester(unittest.TestCase):

    @patch('src.file_b.bar')
    def test_bar(self, mock_bar):
        bar_inst = MagicMock()
        bar_inst.execute.return_value = None
        mock_bar.return_value = bar_inst

        q = qaz()
        q.exec_bar()

This fails every time with something like this:

TypeError: __init__() missing 2 required positional arguments: 'a' and 'b'

This implies the mock isn't working. I can't seem to figure out what I'm getting wrong.

aronchick
  • 6,786
  • 9
  • 48
  • 75

2 Answers2

1

in file_b, you are expecting 2 arguments to be passed in "init"
def __init__(self, a, b):

but in file_a when you are creating object for class bar, you are not passing any arguments
bar_inst = bar()

which is why are you seeing the error
TypeError: __init__() missing 2 required positional arguments: 'a' and 'b'

you do 2 things:

  1. Remove arguments a and b from def __init__(self, a, b):
  2. Pass arguments when

New Solution:

from mock import patch
import unittest
from src.file_a import qaz
from src.file_b import bar

class BarTester(unittest.TestCase):

    @patch.object(bar, '__init__', return_value=None)
    def test_bar(self, *mock_stdout):
        q = qaz()
        q.exec_bar()


Sai Ram
  • 24
  • 2
  • Hi - Unfortunately, this is the problem. I'm using the mocking library to avoid this - it should not require it. I wouldn't mind passing the initialization variables along, but it's execute that's not getting mocked. – aronchick May 13 '20 at 22:23
  • I got it now, I was able to make it work without MagicMock and different import statements. I am not sure, if that's what you are looking for. Solution: Added to my first comment – Sai Ram May 13 '20 at 23:11
  • Oh interesting! At the end of the day, I need to mock BOTH the __init__ and the exec_bar() functions. Is this possible with your method? – aronchick May 13 '20 at 23:29
  • yes, you can achieve that as well. More on how to use patch.object can be found here [patch.object](https://docs.python.org/3/library/unittest.mock.html#patch-object) – Sai Ram May 14 '20 at 00:28
0

Sai Ram solved it, but wanted to post the code for future reference. The test finally looked like this;

from unittest.mock import patch, MagicMock from src.file_a import qaz from src.file_b import bar

class BarTester(unittest.TestCase):

    @patch.object(bar, '__init__', return_value=None)
    @patch.object(bar, 'execute', return_value=None)
    def test_bar(self, *mock_bar):
        q = qaz()
        q.exec_bar()
aronchick
  • 6,786
  • 9
  • 48
  • 75