简体   繁体   中英

How to test if another class method is called within a method in python?

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?

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 .

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. Eg:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM