简体   繁体   中英

How to set a side_effect on an instance method of a class that's been patched?

How do I get a method of a @patch 'ed class to throw an Exception when called?

B is just a class that you can call go() on, which in turn just prints that it happened:

# module_b.py

class B:
  def __init__(self) -> None:
    self.x = True
    print("B constructed OK")
  def go(self):
    print("called B.go()")

A is a class that holds an instance of B . It also has a go() method, which calls the B instance's go() method:

# module_a.py

from module_b import B

class A:
  def __init__(self) -> None:
    try:
      self.b = B()
      print("A constructed OK")
    except Exception as e:
      print("A's constructor threw an exception: " + repr(e))
  def go(self):
    try:
      self.b.go()
      print("b.go() called with no problems")
    except Exception as e:
      print("a.go() threw an exception: " + repr(e))

And here's the test code:

# main.py

from module_a import A
from module_b import B
from unittest import mock

# a = A()
# a.go() # output: called B.go()

@mock.patch("module_a.B") # learned the hard way to do this, not "module_b.B"
def test_b_constructor_throws(mock_b: mock.Mock):
  mock_b.side_effect = Exception("test")
  a = A()
  
print("-- test_b_constructor_throws() --")
test_b_constructor_throws()
print("")
  
@mock.patch("module_b.B.go")
@mock.patch("module_a.B")
def test_b_method_go_throws_1(
    mock_b: mock.Mock,
    mock_b_go: mock.Mock
    ):
      
  # --- attempt 1 ---
  # mock_b_go.side_effect = Exception("test")
  # a = A()
  # a.go()
  
  # --- attempt 2 ---
  mock_b.return_value.mock_b_go.side_effect = Exception("test")
  a = A()
  a.go()
  
print("-- test_b_method_go_throws_1() --")
test_b_method_go_throws_1()
print("")

Finally, here's the output:

-- test_b_constructor_throws() --
B's constructor threw an exception: Exception('test')

-- test_b_method_go_throws_1() --
A constructed OK
b.go() called with no problems

Above code on Trinket.io

I've tried a variety of other things too, like autospec=True and using @patch.object() instead, but no go. I've read a bunch of seemingly related questions but have been unable to come up with a solution:

@jonrsharpes' comments as well as reading his answer here got me where I needed.

  # --- attempt 1 ---
  # mock_b_go.side_effect = Exception("test")
  # a = A()
  # a.go()
  
  # --- attempt 2 ---
  # mock_b.return_value.mock_b_go.side_effect = Exception("test")
  # a = A()
  # a.go()
  
  # --- attempt 3 ---
  mock_b().go.side_effect = Exception("test")
  a = A()
  a.go()

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