mock return value of other class method - python

I have following python code inside a function I call with my pytest:
#function.py
def get_object():
object = manager.get_version(entity)
I want to mock this in my test but I don't know what to use as patch url. I know have:
#patch("functions.get_version")
def test_get_object(get_entities: MagicMock,):
#code with fixture
I don't know if this is even possible or the right approach?

You must mock the object manager from function.
Example:
manager.py
def get_version():
return '0.0.1'
functions.py
import manager
def get_object():
object = manager.get_version()
return object
test_function.py
from unittest.mock import MagicMock, patch
from functions import get_object
#patch("functions.manager")
def test_get_object(get_entities: MagicMock):
get_entities.get_version.return_value = '1.0.0'
assert get_object() == '1.0.0'

Related

Python unit test with mocking assert_called for function outside class

I am trying to test whether a function defined outside of a class is called by a class method.
def function_a(input):
return input
class MyClass:
def __init__(self, user_function=function_a):
self.user_function = user_function
def function_b(input):
return self.user_function(input)
I am trying to test the function call like this:
from unittest import TestCase
from unittest.mock import Mock
class TestMyClass(TestCase):
def test_function_call(self):
my_class = MyClass(user_function=function_a)
mock = Mock()
my_class.function_b(input)
mock.function_a.assert_called()
This gives me
AssertionError: Expected 'function_a' to have been called.
I am using Python 3.6. Looking at the output I can see that function_a was called. What am I doing wrong?
This here did the trick:
from unittest import TestCase
from unittest.mock import MagicMock
class TestMyClass(TestCase):
def test_function_call(self):
my_class = MyClass(user_function=MagicMock())
my_class.function_b(input)
my_class.user_function.assert_called()

Python unittest patch mock entire class

I have a class that I want to patch in my unittests.
class OriginalClass():
def method_a():
# do something
def method_b():
# do another thing
Now I created another class to patch it with, so the code for patching it is like
class MockClass(OriginalClass):
def method_a():
# This will override the original method and return custom response for testing.
patcher = patch('OriginalClass', new=MockClass)
mock_instance = patcher.start()
This works exactly as I want it to and I can return whatever responses required for my unittests.
Now this issue is when I want to verify that a method is called with the right parameters in the unittests.
I tried
mock_instance.method_a.assert_called_once()
But it fail with error AttributeError: 'function' object has no attribute 'assert_called_once'.
How can I test the method calls here?
AttributeError: 'function' object has no attribute 'assert_called_once'.
Once mock object is created, there is no method_a exists, you have to call once m.method_a() before assert.
m = mock.create_autospec(OriginalClass)
m.method_a()
m.method_a.assert_called_once()
patch mock entire class
I took it as mock the whole class and all its methods, I would take an example from here
https://docs.python.org/3.3/library/unittest.mock-examples.html
Applying the same patch to every test method, Here is my example, patch the entire Primary class as MockPrimay for every methods and every tests, setup or SetupClass could be added for the methods needed, even the whole class is mocked, but not every methods to be used in the tests.
from tests.lib.primary_secondary import Secondary
#mock.patch('tests.lib.primary_secondary.Primary')
class TestSecondaryMockPrimary(unittest.TestCase):
def test_method_d(self, MockPrimary):
MockPrimary().process()
MockPrimary().process.return_value = 1
oc = Secondary()
self.assertEqual(oc.method_d(), 1)
import tests
self.assertIs(tests.lib.primary_secondary.Primary, MockPrimary)
The Primary is needed for the Secondary for this test
class Primary(object):
def __init__(self, param):
self._param = param
def process(self):
if self._param == 1:
self._do_intermediate_process()
self._do_process()
class Secondary(object):
def __init__(self):
self.scl = Primary(1)
def method_d(self):
return self.scl.process
I think wraps can be useful here:
from unittest.mock import patch
class Person:
name = "Bob"
def age(self):
return 35
class Double(Person):
def age(self):
return 5
with patch('__main__.Person', wraps=Double()) as mock:
print(mock.name) # mocks data
print(mock.age()) # runs real methods, but still spies their calls
mock.age.assert_not_called()
Output:
<MagicMock name='Person.name' id='139815250247536'>
5
...
raise AssertionError(msg)
AssertionError: Expected 'age' to not have been called. Called 1 times.
Calls: [call()].

Mocking class variable with mocker in pytest

I have a problem roughly looking like this:
In a file data.py I have
from typing import ClassVar
from tinydb import TinyDB
from dataclasses import dataclass
#dataclass
class Data:
db: ClassVar = TinyDB("some_path")
#property
def some_data(self):
return 100
I would like to mock the some_data method.
I tried:
import pytest
import pandas as pd
from package1.data import Data
#pytest.fixture
def mocked_raw_data(mocker):
m = mocker.patch.object(
Data, "some_data", return_value=10, new_callable=mocker.PropertyMock
)
)
return m
def test_some_data(mocked_raw_data):
assert Data().some_data == 2
But obviously this gives an error with the db method class variable. How can I mock this variable as well? Does my approach generally make sense?
Did you use #pytest.mark.django_db?
This would help in testing data on a separate DB rather than the production one.
And regarding your question on mocking, you can use monkey patch for mocking
For eg,
def test_user_details(monkeypatch):
mommy.make('Hallpass', user=user)
return_data =
{
'user_created':'done'
}
monkeypatch.setattr(
'user.create_user', lambda *args, **kwargs: return_data)
user_1 = create_user(user="+123456789")
assert user_1.return_data == return_data

How to mock the cls argument of a classmethod?

I have a class that uses a classmethod as a custom constructor.
# my_module.py
class MyClass:
def __init__(self, my_arg):
self.my_arg = my_arg
#classmethod
def my_constructor(cls):
return cls("my val")
I would like to assert in a test that the constructor has been called with a proper value and the instance returned.
I tried several ways of patching, but I couldn’t get it working.
I tried patching the whole class, using the wraps argument to have the real method executed.
# my_test.py
from unittest import TestCase
from unittest.mock import patch
from my_module import MyClass
class MyClassTestCase(TestCase):
#patch("my_module.MyClass", wraps=MyClass)
def test_my_constructor(self, my_class):
result = my_class.my_constructor()
my_class.assert_called_once_with("my val")
self.assertEqual(result, my_class.return_value)
The problem here is that the cls argument that the _my_module.MyClass.my_class_ method gets is not my Mock, but the real MyClass class.
My other idea was to use patch.object to patch the real __init__ constructor, but that doesn’t work either. This time because __init__ should not return anything, but MagicMock has a return value.
# my_test.py
from unittest import TestCase
from unittest.mock import patch
from my_module import MyClass
class MyClassTestCase(TestCase):
#patch.object(MyClass, "__init__")
def test_my_constructor(self, init):
result = MyClass.my_constructor()
init.assert_called_once_with("my val")
self.assertEqual(result, init.return_value)
Is there an actual way to assert the MyClass class has been instantiated by the _my_constructor_ with the given arguments and returned?
mock __new__ instead __init__
and assert will be
init.assert_called_once_with(MyClass, "my val")

pytest-mock: Mock an abstract class

I'm trying to make the following code work:
from pytest_mock import mocker
class TestClass(mocker):
def setup_method(self):
self.some_mock = SomeAbstractClass()
self.testsubject = ClassThatIsBeingTested(self.some_mock)
def test_1(self):
mocker.patch(self.some_mock, 'some_function', return_value=5)
assert 5 == self.testsubject.function_that_internally_uses_the_mock()
But I get a TypeError for trying to instantiate an abstract class.
How can I mock SomeAbstractClass?
Instead of trying to patch a real instance, you can use the unittest.mock module (also provided as the mock package for Python 2.7) to create a mock instance:
import sys
if sys.version_info[0] == 2:
from mock import Mock
else:
from unittest.mock import Mock
# ...
some_mock = Mock(spec=SomeAbstractClass)
some_mock.some_function.return_value = 5
some_mock.some_function()
# => 5
some_mock.non_existent_function()
# => AttributeError: Mock object has no attribute 'non_existent_function'
This works for creating mock instances of any class—not just abstract ones.
Using pytest-mock or unittest.mockyou can use the mocker.patch.multiple method to override the __abstractmethods__ attribute. By doing that you will be able to create an instance of the abstract class and test the non-abstract methods of it.
Example using pytest and pytest-mock:
def test_something(mocker):
mocker.patch.multiple(ExampleClass, __abstractmethods__=set())
instance = ExampleClass()
...

Categories

Resources