How to test that an object is created by another? - python

I have an object from class A that creates another object from class B using an instance method. And I would like to test it's created correctly with the attribute_to_check with value True in pytest
class B:
def __init__(self, attribute_to_check=None):
self.attribute_to_check = attribute_to_check or False
def some_method():
# some actions...
class A:
def __init__(self, some_attr):
self.some_attr = some_attr
...
async def create_object_b(self, something_not_relevant):
...
object_b = B(attribute_to_check=True)
object_b.some_method()
...
return None
Edit: the method above does not return object_b but rather uses its methods.
And the test would be something like this:
async def test_object_created():
object_A = A(some_attrs)
await object_A.create_object_b(something_not_relevant="")
# How can I access and assert object B is created with attribute_to_check == True?
I tried creating a fixture for the object of class B, but that wouldn't be testing what I intend which is that the function from class A instantiates an object of class B with the expected value for the attribute.

I recommend you to refactor your method create_object_b to just create the b object (consistence with method name and method behavior). This way you can check if B was created with the attributes you want
class B:
def __init__(self, attribute_to_check=None):
self.attribute_to_check = attribute_to_check or False
def some_method():
# some actions...
class A:
def __init__(self, some_attr):
self.some_attr = some_attr
...
async def create_object_b(self, something_not_relevant) -> B:
...
object_b = B(attribute_to_check=True)
...
return object_b
async def make something_with_b(self, object_b: B):
b.some_method()
test class
async def test_object_created():
object_A = A(some_attrs)
object_b = await object_A.create_object_b(something_not_relevant="")
assert object_b.some_attribute == True

Related

How can I dynamically refer to a child class from the super class in Python?

Consider this situation:
class Foo(ABC):
#abstractmethod
def some_method(self):
return
class Bar(Foo):
def some_method(self, param):
# do stuff
return
class Baz(Foo):
def some_method(self, param):
# do stuff differently
return
def do_something_with_obj(some_obj: Foo):
some_param = 'stuff'
some_obj.some_method(some_param)
def main(cond):
if cond:
obj = Bar()
else:
obj = Baz()
do_something_with_obj(obj)
I get an Expected 0 positional arguments error when I try to call some_method() under the do_something_with_obj() method. Of course, this is because I'm essentially calling the abstract method. My question is, how can I dynamically refer to the child class method since I have to choose the right child class based on some condition beforehand?

How to call assert_called_with on mock class while keeping custom return value?

Suppose I want to test a class B and check that its member function foo correctly instantiates and calls a class A and calls the bar method on it. When I mock out A to do this, how do I check that it was correctly called, while ensuring the method still returns its parameter as expected by B?
Here is my attempt:
class B():
def __init__(self):
pass
def foo(self, arg):
a = A()
res = a.bar(arg)
print(f'foo called with {arg} and returned {res}')
assert res == arg
return res
class A():
def bar(self, arg):
return arg
import unittest
import unittest.mock
class MockA:
#unittest.mock.create_autospec
def bar(self, arg):
return arg
#unittest.mock.patch("__main__.A", new=MockA)
class MyTestCase(unittest.TestCase):
def test_case_1(self):
x = B().foo(1)
A.bar.assert_called_with(1)
def test_case_2(self):
x = B().foo(2)
A.bar.assert_called_with(2)
def test_case_3(self):
x = B().foo(3)
A.bar.assert_called_with(3)
MyTestCase().test_case_1()
This fails with an assertion error, since res is <MagicMock name='mock()' id='140545715265664'>. Why does the autospec decorator to MockA.bar ignore the return value in this way?

Create child class object using parent class instance

lets say we have class A and it has one instance - x. How to make a child class of class A where I would be able to pass x as an argument and get all its parameters and pass it to child class object. precisely speaking I want to do something like this.
class A:
def __init__(self, parameter1, parameter2):
self.parameter1 = parameter1
self.parameter2 = parameter2
class B(A):
def __init__(self, Ainstance, someParameter):
super().__init__(**Ainstance.__dict__)
self.someParameter = someParameter
x = A(parameter1='1', parameter2='2')
x = B(x, someParameter='3')
print(x.parameter1)
print(x.parameter2)
print(x.someParameter)
the goal is to create a class where I would be able to get all the parameters of parent class object, and add my own attributes. The problem in the code above is I won't be able to do that with all classes because not all of them has __dict__ attribute.
I have this example code which I use to remind myself how to construct a proxy.
#soProxyPattern
class Example:
def __init__(self):
self.tag_name = 'name'
def foo(self):
return 'foo'
def bar(self, param):
return param
class Container:
def __init__(self, contained):
self.contained = contained
self.user_name = 'username'
def zoo(self):
return 0
def __getattr__(self, item):
if hasattr(self.contained, item):
return getattr(self.contained,item)
#raise item
c = Container(Example())
print(c.zoo())
print(c.foo())
print(c.bar('BAR'))
print(c.tag_name)
print(c.user_name)
The output is:
0
foo
BAR
name
username
This shows that Container can have its own attributes (methods or variables) which you can access over and above all of the attributes of the contained instance.
Instead of dict you could use the dir and getattr like this:
class A:
def __init__(self, parameter1, parameter2):
self.parameter1 = parameter1
self.parameter2 = parameter2
class B(A):
def __init__(self, Ainstance, someParameter):
parameters = {param: getattr(Ainstance, param) for param in dir(Ainstance) if not param.startswith("__")}
super().__init__(**parameters)
self.someParameter = someParameter
For a more detailed explanation see: Get all object attributes in Python?

Class method don't update attribute

I have this code:
class Test:
def __init__(self, a):
self.a = a
self.success = True
def method(self):
self.success = False
test = Test("tree")
test.method
print(test.success)
#output is: True
I need to check if the operation programmed in "method" is successful. So, on success, I update the "success" attribute declared in the constructor. But when I call the method after creating the class object, the attribute is not updated.
To invoke a method,you have to use parenthesis. In short,
test.method() is the correct way to call the method.
You're not calling your method() correctly.
class Test:
def __init__(self, a):
self.a = a
self.success = True
def method(self):
self.success = False
test = Test("tree")
test.method() # NOTE the parentheses here
print(test.success)

How to access property cross class and cross file in Python?

Now I need a property which in another class to do something in one class.
just like:
a.py
class A:
def __init__(self, io_loop): # the same io_loop instance
self.access = None
self.w_id = None
self.io_loop = io_loop
#gen.coroutine
def setup(self):
# `async_client` has the `get`, 'post', 'put', 'delete' methods
self.access = yield async_client()
#gen.coroutine
def do_something(self):
self.w_id = self.access.get('w_id')
...
def run(self):
self.io_loop.run_sync(self.setup)
self.io_loop.spawn_callback(self.do_something)
self.io_loop.start()
if __name__ == '__main__':
a = A()
a.run()
-
b.py
class B:
def __init__(self, io_loop):
self.w_id = None
self.io_loop = io_loop # the same io_loop instance
# How can i get the w_id from `class A`
def run(self):
...
if __name__ == '__main__':
b = B()
b.run()
Notice:
when zone_id of class B is not None, class B can do next. that's means, if class A zone_id is None, class B will waiting for it.
And the class A and class B only could initialize one instance.
the class A and class B in differents files.
You can't access that variable until you create an instance that initializes. Otherwise, w_id doesn't exist in A.
If you want to give w_id an arbitrary value for access from other classes, put it as a class variable, means you write directly w_id = 'some value' inside class A with the same indentation as the defs:
class A:
w_id = something
def __init__(self):
...
class B:
def __init__(self):
self.w_id = A.w_id
Otherwise, you need an instance of A, like that:
class B:
def __init__(self):
a = A()
a.do_something()
self.w_id = a.w_id
The only other option is to create the same functions inside B:
class B:
...
#gen.coroutine
def setup(self):
# `async_client` has the `get`, 'post', 'put', 'delete' methods
self.access = yield async_client()
#gen.coroutine
def do_something(self):
self.w_id = self.access.get('w_id')
...
As you mentioned that io_loop is the same instance in all of the classes, it might occur that you need to create a copy of it if your functions uses it. You can't change a variable and expect it to stay unchanged.

Categories

Resources