Reputation: 31
function_one.py
class FunctionOne(Base):
def __init__(self, amount, tax):
super().__init__(amount, tax)
function_two.py
Class FunctionTwo:
def __init__(self, a, b, c):
self.__a = a
self.__b = b
self.__c = c
def _get_info(self):
x = FunctionOne(0, 1)
return x
test_function_two.py
class TestPostProcessingStrategyFactory(unittest.TestCase):
def test__get_info(self):
a = “a”
b = “b”
c = “c”
amount = 0
tax = 1
function_two = FunctionTwo(a, b, c)
assert function_two.__get_info() == FunctionOne(0,1)
I am trying to create unit test for the function_two.py source code. I get the assertion error that the object at ******** != object at *********. So the two objects address is different. How can make this test pass by correcting the assert statement
assert function_two.__get_info() == FunctionOne(0,1)
Upvotes: 1
Views: 114
Reputation: 18693
You need to understand that equality comparisons depend on the __eq__
method of a class. From the code you provided it appears that simply initializing two objects of FunctionOne
with the same arguments does not result in two objects that compare as equal. Whatever implementation of __eq__
underlies that class, only you know that.
However, I would argue the approach is faulty to begin with because unit tests, as the name implies, are supposed to isolate your units (i.e. functions typically) as much as possible, which is not what you are doing here.
When you are testing a function f
that calls another of your functions g
, strictly speaking, the correct approach is mocking g
during the test. You need to ensure that you are testing f
and only f
. This extends to instances of other classes that you wrote, since their methods are also just functions that you wrote.
Have a look at the following example code.py
:
class Foo:
def __init__(self, x, y):
...
class Bar:
def __init__(self, a, b):
self.__a = a
self.__b = b
def get_foo(self):
foo = Foo(self.__a, self.__b)
return foo
Say we want to test Bar.get_foo
. That method uses our Foo
class inside it, instantiating it and returning that instance. We want to ensure that this is what the method does. We don't want to concern ourselves with anything that relates to the implementation of Foo
because that is for another test case.
What we need to do is mock that class entirely. Then we substitute some unique object to be returned by calling our mocked Foo
and check that we get that object from calling get_foo
.
In addition, we want to check that get_foo
called the (mocked) Foo
constructor with the arguments we expected, i.e. with its __a
and __b
attributes.
Here is an example test.py
:
from unittest import TestCase
from unittest.mock import MagicMock, patch
from . import code
class BarTestCase(TestCase):
@patch.object(code, "Foo")
def test_get_foo(self, mock_foo_cls: MagicMock) -> None:
# Create some random but unique object that should be returned,
# when the mocked class is called;
# this object should be the output of `get_bar`:
mock_foo_cls.return_value = expected_output = object()
# We remember the arguments to initialize `bar` for later:
a, b = "spam", "eggs"
bar = code.Bar(a=a, b=b)
# Run the method under testing:
output = bar.get_foo()
# Check that we get that EXACT object returned:
self.assertIs(expected_output, output)
# Ensure that our mocked class was instantiated as expected:
mock_foo_cls.assert_called_once_with(a, b)
That way we ensure proper isolation from our Foo
class during the Bar.get_foo
test.
Side note: If we wanted to be super pedantic, we should even isolate our test method from the initialization of Bar
, but in this simple example that would be overkill. If your __init__
method does many things aside from just setting some instance attributes, you should definitely mock that during your test as well.
Hope this helps.
References:
Mock
classpatch
decoratorTestCase.assertIs
Mock.assert_called_once_with
Upvotes: 1