13

I am noticing a weird behavior with assert_called_once and assert_called_once_with in python. This is my real simple test:

File module/a.py

from .b import B

class A(object):
    def __init__(self):
        self.b = B("hi")

    def call_b_hello(self):
        print(self.b.hello())

File module/b.py

class B(object):
    def __init__(self, string):
        print("created B")
        self.string = string;

    def hello(self):
        return self.string

These are my tests:

import unittest
from mock import patch
from module.a import A    

class MCVETests(unittest.TestCase):
    @patch('module.a.B')   
    def testAcallBwithMockPassCorrect(self, b1):
        a = A()
        b1.assert_called_once_with("hi")
        a.call_b_hello()
        a.b.hello.assert_called_once()

    @patch('module.a.B')
    def testAcallBwithMockPassCorrectWith(self, b1):
        a = A()
        b1.assert_called_once_with("hi")
        a.call_b_hello()
        a.b.hello.assert_called_once_with()

    @patch('module.a.B')
    def testAcallBwithMockFailCorrectWith(self, b1):
        a = A()
        b1.assert_called_once_with("hi")
        a.b.hello.assert_called_once_with()

    @patch('module.a.B')
    def testAcallBwithMockPassWrong(self, b1):
        a = A()
        b1.assert_called_once_with("hi")
        a.b.hello.assert_called_once()

if __name__ == '__main__':
    unittest.main()

My problem as stated in the name of the function is:

  • Test 1 passes correctly
  • Test 2 passes correctly
  • Test 3 fails correctly (I've removed the call to b)
  • Test 4 passes I am not sure why.

Am I doing something wrong? I am not sure but reading the documentation docs python:

assert_called_once(*args, **kwargs)

Assert that the mock was called exactly once.

Community
  • 1
  • 1
asgarro
  • 131
  • 1
  • 1
  • 8
  • I can't actually reproduce this. Both 3 and 4 fail in my case. What version of Python and what version of the `mock` library do you use? I tested with Python 3.6 (and used the stdlib `unittest.mock`). – Martijn Pieters Feb 17 '17 at 12:22
  • I was using python2.7, I'll change the code and check with python3.5 thanks :) – asgarro Feb 17 '17 at 13:30
  • 3
    In 3.5 that function does not exist, so I will solve the problem using this way: assert a.b.hello.call_count == 1 https://engineeringblog.yelp.com/2015/02/assert_called_once-threat-or-menace.html – asgarro Feb 17 '17 at 13:33
  • I can't reproduce this in Python 2.7 *either*, using `mock` version 2.0.0. – Martijn Pieters Feb 17 '17 at 13:42
  • I am not sure what to say. I had this issue and I am rewriting all the tests to fix the issue. In version 3.5 I get: raise AttributeError(name) AttributeError: assert_called_once In version 2.7 I get pass. I don't have access to version 3.6. Please close/delete the question if it is inappropriate, the fix for me is to use a workaround at this point :) – asgarro Feb 17 '17 at 15:36
  • I didn't say it was inappropriate. I just can't reproduce your problem. I stated the Python and library versions; when I put your `a.py` and `b.py` into a directory `module` (with an empty `__init__.py` then use `python2.7 tests.py` to run your `TestCase`s, I get the expected 2 failures. – Martijn Pieters Feb 17 '17 at 15:38
  • And indeed, in Python 3.5 you get an `AttributeError`, but you can install `mock` in Python3.5 too. :-) I just did, and I get the expected 2 assertion errors. – Martijn Pieters Feb 17 '17 at 15:42
  • Yeah for environment problem I can't install anything on the machines, so I'll have to cope with python2.7/3.5 and mock 1.0.1 :D this looks a version problem that was fixed but I can't really enjoy the fix :) – asgarro Feb 17 '17 at 15:55

1 Answers1

10

This is old, but for others landing here...

For python < 3.6, assert_called_once isn't a thing and so you're actually making a mocked function call which doesn't error

Please see: http://engineroom.trackmaven.com/blog/mocking-mistakes/

You can check the call count instead.

Suzana
  • 4,251
  • 2
  • 28
  • 52
Curt
  • 149
  • 1
  • 4