0

I want to make my tests "real" unittests in a strict meaning. There shouldn't be any dependencies. All dependencies should be mocked.

The class Bar in module bar need to be tested. But in some situations it will have a member of type Foo from module foo. The goal is that the unittest does not have to import foo or foo.Foo.

My mocking seems to work. But I'm not sure how to test if Bar() now does have tried to instantiate foo.Foo(). My assert_called() in the below example failed with Expected 'mock' to have been called.. And that assert also doesn't give me all information's I want.

This is the test code:

#!/usr/bin/env python3 import unittest from unittest import mock import bar # The goal ist to test "Bar" wihtout importing "foo.Foo" as an extra dependency class MyTest(unittest.TestCase): def test_bar(self): mock_foo = mock.Mock() bar.foo = mock_foo b = bar.Bar(7) print('') print(f'{mock_foo=}') print(f'{b.y=}') # Of course this doesn't work, because "foo" is not imported # self.assertIsInstance(b.y, foo.Foo) print(mock_foo.__dict__) mock_foo.assert_called() # failes def test_int(self): b = bar.Bar(8) self.assertIsInstance(b.y, int) if __name__ == '__main__': unittest.main() 

Here comes module bar:

import foo class Bar: def __init__(self, y): if y == 7: self.y = foo.Foo(7) else: self.y = y 

And this is module foo:

class Foo: def __init__(self, x): self.x = x 
1
  • 2
    Strive to avoid dependencies in the first place. Bar.__init__ can take an optional argument (defaulting to foo.Foo) to call when necessary. Then to test, you need only make a call like b = bar.Bar(7, mock_foo). Commented Feb 12, 2023 at 16:32

1 Answer 1

1

When you're mocking, you should really be using mock.patch() to do your patching.

consider, instead:

#!/usr/bin/env python3 import sys import unittest from unittest import mock import bar class MyTest(unittest.TestCase): @mock.patch('foo.Foo') def test_bar(self, foo_mock): b = bar.Bar(7) # This _does_ work, because the patch decorator gives us the patched # mock. # this is something you should _never_ include in a proper unit test, # but here to demonstrate the patching self.assertIs(foo_mock, sys.modules['foo'].Foo) foo_mock.assert_called_once_with(7) def test_no_foo(self): for test_val in [0, True, False, None, 13, 666]: with self.subTest(test_val=test_val): b = bar.Bar(test_val) self.assertEqual(b.y, test_val) if __name__ == '__main__': unittest.main() 
Sign up to request clarification or add additional context in comments.

1 Comment

This includes some additional improvements to the original posted test (not sure if you artificially simplified the tests for posting, though). * in MyTest.test_bar(), I test that foo.Foo is called once, with 7 as the sole argument * in MyTest.test_no_foo() (renamed), I test more of the interface of the function as it exists, and I test that the value is the expected actual value, not just of the same type

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.