0

I am trying to unit test the compare_vals method below:

class Class:
    def compare_vals(self, input_value):

        if input_value > 3:
            return True

        out_value = self.do_something()
        return out_value

    def do_something(self):
        return False

More specifically, I want to test if self.do_something() is being called in case the if-statement evaluates False.

I have written the following unit test:

import pytest
from unittest import mock
import costa_test.genericfunctions.simplefunctions as sf

@mock.patch("costa_test.genericfunctions.simplefunctions.Class.do_something")
def test_compare_vals(mock_do_something):
    compare_obj = sf.Class()
    out_value = compare_obj.compare_vals(2)

    assert out_value is True
    assert mock_do_something.call_count == 1

I expected that mock_do_something.call_count would return the value 1 in this case, since the if-statement evaluates False and do_something is called once.

However, when I run pytest, I get the following:

FAILED tests/test_simplefunctions.py::test_compare_vals - AssertionError: assert <MagicMock name='do_something()' id='140474257049040'> is True

How can I correctly check if the do_something method is being called?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
laurentius
  • 11
  • 2
  • The failure is nothing to do with the call count, it's the assertion on the line before. You never set a return value for the mock method, and if you did why would you pick _`True`_? But really you shouldn't be doing this at all; just assert that the call to `compare_vals` returns `False`. The fact that it does so by calling another method internally is just that: _internal_. It's an implementation detail, don't couple your tests to it. – jonrsharpe Jun 02 '22 at 07:41
  • 2 is not greater than 3. `out_value` is therefore `False`. `assert out_value is True` therefore fails. – blhsing Jun 02 '22 at 07:49
  • @jonrsharpe @blhsing: You are right indeed. And indeed, if I change the assert of `compare_vals` to False and add `mock_do_something.return_value = False` everything is working fine. I am just surprised that the first assert is affecting the second one. Shouldn't the 2nd assert not test the number of calls to `do_something()` independent of the result of the first assert? – laurentius Jun 02 '22 at 08:30
  • But the point remains that you shouldn't be doing that at all. The return value was already False _before_ you started interfering with the implementation of the thing you were supposed to be testing. – jonrsharpe Jun 02 '22 at 08:30
  • But in that case it wouldn't be a clean unit test, since I would indirectly be testing `do_something` as well. Therefore I was mocking it in the first place. – laurentius Jun 02 '22 at 08:34
  • That's not true, it's less clean to mock parts of the thing you're testing. Test doubles are for _collaborators_. Your tests should reflect _behaviour_, not implementation details. Yes you're indirectly testing `do_something`, but so what? That _is_ being used. And if you decided to inline that logic, why would you want to also have to change the _test_? Here's an example of why not to do this (in JS, but the principles are universal): https://stackoverflow.com/a/66752334/3001761. – jonrsharpe Jun 02 '22 at 08:45

0 Answers0