0

I've got a really useful python method like this:

def stop_widget(): original_widget = load_widget_from_file() if original_widget: original_widget.close() 

when I want to test it to make sure I called close(), I do:

@patch('load_widget_from_file') def test_stop_widget_with_original_widget(self, lwff_mock): mock_widget = create_autospec(Widget) lwff_mock.return_value = mock_widget stop_widget() mock_widget.close.assert_called_once_with() 

but what do I do when I want to test not calling close when the return value of load_widget_from_file doesn't evaluate to True?

If I tried making another unit test with:

@patch('load_widget_from_file') def test_stop_widget_with_original_widget(self, lwff_mock): mock_widget = None lwff_mock.return_value = mock_widget stop_widget() mock_widget.close.assert_not_called() 

this would blow up.

4
  • What about assert_not_called? Commented Sep 15, 2017 at 13:45
  • @larsks, I don't have an object instantiated with a function to call that on. Commented Sep 15, 2017 at 14:05
  • what happens if you just do mock_widget = create_autospec(Widget) in the second method, just like in the first method? Commented Sep 15, 2017 at 14:13
  • @rick, that fails because close is called (this would make it identical to the first case) Commented Sep 15, 2017 at 14:14

1 Answer 1

2

You need to create a second mock object (instead of setting mock_widget = None), but the widget needs to be falsey to prevent the function from entering the if condition.

In Python, an object is always "truthy" unless is has a zero-length, or it has a __bool__ method that returns False:

object.__bool__(self)

Called to implement truth value testing and the built-in operation bool(); should return False or True. When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __bool__(), all its instances are considered true.

Probably the "right way" to add a __bool__ method to your mock object would be to use MagicMock, which comes with many of the Python "magic methods" pre-defined. But you'll also have to change the return value to False, like so:

@patch('load_widget_from_file') def test_stop_widget_with_original_widget(self, lwff_mock): mock_widget = MagicMock() mock_widget.__bool__.return_value = False lwff_mock.return_value = mock_widget stop_widget() mock_widget.close.assert_not_called() 
Sign up to request clarification or add additional context in comments.

3 Comments

Yeah, the first way doesn't work - bool is not defined in the original class so I think create_autospec doesn't go in and make it (at least not the version I'm running Python 3.5.1, I looked at some changelogs for the unittest framework and it looked like someone implemented some magicmethod for bool a long time ago, but I don't see docs for it.
yeah I didn't bother testing. deleted the first idea- not sure why it isn't working but whatever.
I tried the way you have mentioned but for Python 3.6 the above solution was not working.Changed the code lwff_mock.return_value.__bool__.return_value = False and it worked.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.