Tuesday, January 8, 2013

ExpectedMockCreationError: Verify: Expected mocks never created:

I've been writing some unit tests for my code using pymox. This is (a simplified version) of the code I was testing, found in a python module called hashtag.py:

def Authorize():
  """Authorizes the user.

  Returns:
    An authorized instance of httplib2.Http.
  """

  oauth_client = oauth.OAuth()
  credentials = oauth_client.Flow(SCOPES)
  auth_http = oauth_client.Authorize(credentials)
  return auth_http

And here's the (simplified) code I wrote to test:

import hashtag
...

class HashtagTest():
  ...

  def testAuthorize(self):
    """Test the authorize method."""

    expected_auth_http = self.mox.CreateMock(httplib2.Http)

    self.mox.StubOutClassWithMocks(oauth, 'OAuth')
    mock_oauth = oauth.OAuth()
    mock_credentials = self.mox.CreateMock(client.OAuth2Credentials)
    mock_oauth.Flow(mox.IsA(list)).AndReturn(mock_credentials)
    mock_oauth.Authorize(mock_credentials).AndReturn(expected_auth_http)
    self.mox.ReplayAll()

    actual_auth_http = hashtag.Authorize()
    self.assertEquals(expected_auth_http, actual_auth_http)

While writing the tests, I ran into the following error:

Traceback (most recent call last):
  File ".../hashtag/hashtag_test.py", line 34, in tearDown
    self.mox.VerifyAll()
  File ".../mox/mox.py", line 333, in VerifyAll
    mock_obj._Verify()
  File ".../mox/mox.py", line 958, in _Verify
    raise ExpectedMockCreationError(self._instance_queue)
ExpectedMockCreationError: Verify: Expected mocks never created:
  0.  <MockAnything instance of OAuth>

This isn't very clear, but I do see that the error is being raised during the verifyAll step. A Google search for the error led me to the code, with the following docstring explaining the error:

Raised if mocks should have been created by StubOutClassWithMocks.

Looking at the Mox Documentation, the general workflow is as follows:
  1. Create mock (in record mode)
  2. Set up expectations
  3. Put mock into replay mode
  4. Run test
  5. Verify expected interactions with the mock occurred
I created a mock and set up the expectations that my code will create a mock object of oauth.OAuth and run some of it's methods. I replayed the code and then run the code to test. When verifying that the expectations matched the actual code, there was an issue. But what is the issue? It looks like this should work!

Luckily, in programming, there's often more than one way to do things. So, I tried a different approach. I rewrote my test as follows:

import hashtag
...

class HashtagTest():
  ...

  def testAuthorize(self):
    """Test the authorize method."""

    expected_auth_http = self.mox.CreateMock(httplib2.Http)

    mock_oauth = oauth.OAuth()
    self.mox.StubOutWithMock(mock_oauth, 'Flow')
    self.mox.StubOutWithMock(mock_oauth, 'Authorize')
    mock_credentials = self.mox.CreateMock(client.OAuth2Credentials)
    mock_oauth.Flow(mox.IsA(list)).AndReturn(mock_credentials)
    mock_oauth.Authorize(mock_credentials).AndReturn(expected_auth_http)
    self.mox.ReplayAll()

    actual_auth_http = hashtag.Authorize()
    self.assertEquals(expected_auth_http, actual_auth_http)

At this point, the error changed:

Traceback (most recent call last):
  File ".../hashtag/hashtag_test.py", line 49, in testAuthorize
    actual_auth_http = hashtag.Authorize()
AttributeError: 'module' object has no attribute 'Authorize'

This error is much more clear; I've seen and dealt with this before. I looked at my import statements and the general structure of my code and found an easy solution:

My hashtag.py module was, in fact, in a directory titled hashtag (maybe poor naming on my part..). The import statement was importing the directory rather than the module. Therefore, I simply had to update my original code to the following in order for the test to work:

from hashtag import hashtag
...

class HashtagTest():
  ...

  def testAuthorize(self):
    """Test the authorize method."""

    expected_auth_http = self.mox.CreateMock(httplib2.Http)

    self.mox.StubOutClassWithMocks(oauth, 'OAuth')
    mock_oauth = oauth.OAuth()
    mock_credentials = self.mox.CreateMock(client.OAuth2Credentials)
    mock_oauth.Flow(mox.IsA(list)).AndReturn(mock_credentials)
    mock_oauth.Authorize(mock_credentials).AndReturn(expected_auth_http)
    self.mox.ReplayAll()

    actual_auth_http = hashtag.Authorize()
    self.assertEquals(expected_auth_http, actual_auth_http)

This wasn't the only time the ExpectedMockCreationError error cropped up. In another test, I accidentally created a local variable called hashtag. Now, hashtag no longer referred to the module but the local variable.

In general, this error can happen for several reasons. One way to help figure out the problem is to rewrite the code as I did above - rather than stubbing out the entire class with mocks, create an instance of the class and stub out the methods.