Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asserting that __init__ was called with right arguments

Tags:

I'm using python mocks to assert that a particular object was created with the right arguments. This is how my code looks:

class Installer:     def __init__(foo, bar, version):         # Init stuff         pass     def __enter__(self):         return self      def __exit__(self, type, value, tb):         # cleanup         pass      def install(self):         # Install stuff         pass  class Deployer:     def deploy(self):         with Installer('foo', 'bar', 1) as installer:             installer.install() 

Now, I want to assert that installer was created with the right arguments. This is the code I have so far:

class DeployerTest(unittest.TestCase):     @patch('Installer', autospec=True)     def testInstaller(self, mock_installer):         deployer = Deployer()         deployer.deploy()          # Can't do this :-(         mock_installer.__init__.assert_called_once_with('foo', 'bar', 1) 

This is the error I get:

  File "test_deployment.py", line .., in testInstaller     mock_installer.__init__.assert_called_once_with('foo', 'bar', 1) AttributeError: 'function' object has no attribute 'assert_called_once_with' 

Here is the fixed code (Call it test.py). Thanks, all!

import unittest from mock import patch  class Installer:     def __init__(self, foo, bar, version):         # Init stuff         pass      def __enter__(self):         return self      def __exit__(self, type, value, tb):         # cleanup         pass      def install(self):         # Install stuff         pass  class Deployer:     def deploy(self):         with Installer('foo', 'bar', 1) as installer:             installer.install()  class DeployerTest(unittest.TestCase):     @patch('tests.test.Installer', autospec=True)     def testInstaller(self, mock_installer):         deployer = Deployer()         deployer.deploy()          # Can't do this :-(         # mock_installer.__init__.assert_called_once_with('foo', 'bar', 1)          # Try this instead         mock_installer.assert_called_once_with('foo', 'bar', 1) 
like image 753
Srikanth Avatar asked Feb 29 '16 23:02

Srikanth


People also ask

What is MagicMock Python?

MagicMock. MagicMock objects provide a simple mocking interface that allows you to set the return value or other behavior of the function or object creation call that you patched. This allows you to fully define the behavior of the call and avoid creating real objects, which can be onerous.

What is Side_effect in mock python?

side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT , the return value of this function is used as the return value.

What does mock patch do?

mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.


1 Answers

So, the error message you are getting is actually because you are not checking your mock properly. What you have to understand here is that in your decorator you are ultimately saying that, the call to Installer will relturn a Mock object instead.

Therefore, for any call to Installer() with respect to where you are patching, the return value of that will call Mock() instead.

So, the assertion you actually want to check is simply at the mock_installer, and not the mock_installer.__init__.:

mock_installer.assert_called_once_with('foo', 'bar', 1) 

Here is the modification made to your code:

class DeployerTest(unittest.TestCase):      @patch('Installer', autospec=True)     def testInstaller(self, mock_installer):         deployer = Deployer()         deployer.deploy()          mock_installer.assert_called_once_with('foo', 'bar', 1) 

A little extra information to provide some more explanation, if you were testing now if install was called within your context manager, you have to realize here that you actually have to check inside your __enter__, so a structure would be like this:

For clarity sake create a mock_obj in your test method and:

mock_obj = mock_installer.return_value 

Now, within your context manager, you will need to look inside the call to __enter__(). In case you don't know why this is, read up on context managers.

So, with that in mind, you simply perform your check as:

mock_obj.__enter__().install.assert_called_once_with() 
like image 109
idjaw Avatar answered Oct 28 '22 18:10

idjaw