0

I have the following structure:

ClassB():
 def foo():
Class A():
 def __init__(self, B):
 #some initialisations
 def method1():
 #complex logic
 B.foo()

I am trying to write a unit test method1 and would like to test if foo is called once or not. How I can achieve this? What should I mock?

asked Jun 22, 2020 at 13:25

2 Answers 2

3

Edited

Based on the further information provided by OP, a rework on the answer was done.

Code

The code below has been tested locally with Python3.8.3 on CentOS 8. Run python3 -m unittest to see the test result.

Functional code(sub.py):

class B(): 
 def foo(self): 
 pass 
 
 
class A(): 
 def __init__(self, B): 
 self.b = B 
 
 def method1(self): 
 self.b.foo()

Test code(test.py):

from unittest import TestCase 
from unittest.mock import patch 
 
from sub import A, B 
 
 
class Test(TestCase): 
 def test_A(self): 
 with patch('sub.B.foo') as mock_foo: 
 a = A(B) 
 a.method1() 
 mock_foo.assert_called_once()

Basically the test code tries to mock the B.foo method and checks if the method has been called EXACTLY ONCE when A.method1 is invoked.

Test Explanation

  1. a = A(B) line does not call B.foo
  2. a.method1() line calls B.foo

In total, B.foo is called exactly once so mock_foo.assert_called_once() will pass. If any of the arguments above turns out to be invalid, the assertion will fail. In case you just need to check that B.foo has been called at least once, use mock_foo.assert_called() instead.

For details of the mock system, I suggest to read the official docs.

answered Jun 22, 2020 at 13:54
Sign up to request clarification or add additional context in comments.

3 Comments

Are you sure it's called twice inside the patch block? assert_called_once indeed checks for exactly one call.
@xiao, I cant just call A(), I should be passing B to it as A(B), should I be passing a mock of B?
Ok. As to your question - you can construct an instance of B and pass it as parameter to A(). If that is not possible, you can indeed mock ClassB instead of ClassB.foo, and use classb_mock.return_value.foo.assert_called... instead.
2

You should create a Mock for B, pass it to the constructor of A and check if the function was called once.

You can write the Mock by yourself. E.g.:

class B_Mock():
 def __init__(self):
 self.foo_calls = 0
 def foo(self):
 self.foo_calls += 1

And than check the attr foo_calls of your B_Mock instance with assert

answered Jun 22, 2020 at 13:30

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.