Python mocking class instantiation and accessing private member variable - python

I want to test a method inside a class which updates the value of a member variable. However class takes constructor arguments which are not required in the method to test.
class SimpleClass(Database):
count = None
def intoTwo(self, v):
self.count = 2*v
Now I am testing method as follows
import unittest
import mock
class TestSimpleClass(unittest.TestCase):
#mock.patch('SimpleClass', autospec=True)
def test_intoTwo(self, mock_simpleclass):
mock_instance = mock_simpleclass.return_value
mock_instance.intoTwo(2)
self.assertEqual(mock_instance.count,4)
I am getting following error:
<NonCallableMagicMock name='SimpleClass().count' id='139921148836112'>
Please suggest the solution for this. I count not find something relevant in other posts or blogs.

Related

Mypy plugin for dectorator that registers attributes

I am trying to write a mypy plugin that allows mypy to know about instance attributes that are getting added dynamically via some decorator of my package.
This decorator works as follows:
# module
class A:
pass
def register_with_a(name):
def inner(cls):
A.name = cls # actual code does some destriptor magic to work with instances
return cls
return inner
This lets the user write custom accessors, e.g.:
# user code
#module.register_with_a("x")
class X:
pass
a = module.A()
a.x # should be class X
Now I want to enable this via a mypy plugin (first question: does this even work?)
For now I have this:
# mypy_plugin
from mypy.plugin import Plugin
from mypy.plugins.common import add_attribute_to_class
def register_fallback(ctx):
name = ctx.reason.args[0].value
add_attribute_to_class(
api=ctx.api,
cls=???, # How to get the ClassDef from module.A?
name=name,
typ=???, # What is this exactly?
)
class APlugin(Plugin):
def get_class_decorator_hook(fullname):
if fullname == "module.register_with_a":
return register_callback
return None
def plugin(version):
return APlugin
I managed to get the "name" argument of the decorator.
Am I even allowed to call add_attribute_to_class in this context?
How do I get the ClassDef of my module class?
What is the Type of the decorated class and how do I get it?

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()].

Unable to access instantiated data member in python

I'm having problem accessing the data member in python. Not sure why.
These are my files:
# main.py
from myprocess import DataProcess as dp
myprocess = dp('apple')
myprocess.process_files()
Now for the file where i have a class
#myprocess.py
class DataProcess:
def __init__(self, file1):
self.file1=file1
#classmethod
def process_files():
print(self.file1)
In the process_files method, I have an error :
Class 'DataProcess' has no 'file1' member
Where have I gone wrong?
You can't use self parameter inside a classmethod. The idea of class method is that the method belongs to the class itself, and not to an instance of the class. Hence if you delete the #classmethod decorator, your code should work

Passing extra argument to TestCase Setup

I am writing tests for my django app using TestCase, and would like to be able to pass arguments to a parent class's setUp method like so:
from django.test import TestCase
class ParentTestCase(TestCase):
def setUp(self, my_param):
super(ParentTestCase, self).setUp()
self.my_param = my_param
def test_something(self):
print('hello world!')
class ChildTestCase(ParentTestCase):
def setUp(self):
super(ChildTestCase, self).setUp(my_param='foobar')
def test_something(self):
super(ChildTestCase, self).test_something()
However, I get the following error:
TypeError: setUp() takes exactly 2 arguments (1 given)
I know that this is because only self is still passed, and that I need to overwrite to class __init__ to get this to work. I am a newbie to Python and not sure how to implement this. Any help is appreciated!
The test runner will call your ParentTestCase.setup with only self as a parameter. Therefore you will add a default value for this case e.g.:
class ParentTestCase(TestCase):
def setUp(self, my_param=None):
if my_param is None:
# Do something different
else:
self.my_param = my_param
Note: be careful not to use mutable values as defaults (see "Least Astonishment" and the Mutable Default Argument for more details).

Define a method outside of class definition?

class MyClass:
def myFunc(self):
pass
Can I create MyFunc() outside of the class definition, maybe even in another module?
Yes. You can define a function outside of a class and then use it in the class body as a method:
def func(self):
print("func")
class MyClass:
myMethod = func
You can also add a function to a class after it has been defined:
class MyClass:
pass
def func(self):
print("func")
MyClass.myMethod = func
You can define the function and the class in different modules if you want, but I'd advise against defining the class in one module then importing it in another and adding methods to it dynamically (as in my second example), because then you'd have surprisingly different behaviour from the class depending on whether or not another module has been imported.
I would point out that while this is possible in Python, it's a bit unusual. You mention in a comment that "users are allowed to add more" methods. That sounds odd. If you're writing a library you probably don't want users of the library to add methods dynamically to classes in the library. It's more normal for users of a library to create their own subclass that inherits from your class than to change yours directly.
I'd also add a reminder that functions don't have to be in classes at all. Python isn't like Java or C# and you can just have functions that aren't part of any class. If you want to group together functions you can just put them together in the same module, and you can nest modules inside packages. Only use classes when you need to create a new data type, not just to group functions together.
You can define a function outside of a class and then add it. However, there is a subtle difference in assigning the function to the class or to the instance object. Here is an example:
class MyClass1(object):
def __init__(self, bar):
self.foo = 'up'
MyClass1.foobar = bar
class MyClass2(object):
def __init__(self, bar):
self.foo = 'up'
self.foobar = bar
def bar(self):
return "What's " + self.foo
Let's first look at what is happening in MyClass1. foobar in this class is similar to a normal method as though it was defined inside the class definition (i.e. it is a method bound to the instance of this class). Let's take a look at what this looks like...
In [2]: x = MyClass1(bar)
In [3]: x.foobar
Out[3]: <bound method MyClass1.bar of <__main__.MyClass1 object at 0x104346990>>
In [4]: x.foobar()
Out[4]: "What's up"
How does this differ from MyClass2? In MyClass2, foobar is simply a reference to the bar function and is NOT a bound method. Because of this we must pass the instance in for this function to work properly. e.g.
In [5]: y = MyClass2(bar)
In [6]: y.foobar
Out[6]: <function __main__.bar>
In [7]: y.foobar()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-6feb04878e5f> in <module>()
----> 1 y.foobar()
TypeError: bar() takes exactly 1 argument (0 given)
In [8]: y.foobar(y)
Out[8]: "What's up"
Although I'm not sure if this is ever good practice to be doing it this way...
Yes you can definitely have functions outside of a class. Here is a mini example...
def date_parse(date_string):
return date(date_string)
class MyClass:
def myFunc(self):
pass
def myDateFunc(self, date_string):
self.date = date_parse(date_string)
I give a shoot at what you are looking for, where one class Helper provides functions to a specialized class (MyClass)
class Helper(object):
def add(self, a, b):
return a + b
def mul(self, a, b):
return a * b
class MyClass(Helper):
def __init__(self):
Helper.__init__(self)
print self.add(1, 1)
if __name__ == '__main__':
obj = MyClass()
This will print
>>> 2
You can!
For example:
In django this is the view function and it just stay in the views module in my app
def user_list_view(request):
queryset = User.objects.all()
return render(request, 'list_user_users.html', {'object_list': queryset})
And in the url routing module I just import it from the module and use it there is no class whatsoever
from . import views
from django.urls import path
urlpatterns = [
# homepage of app
path('', views.user_list_view),

Categories

Resources