i have this piece of code which is a class __init__ method and takes two arguments.
def __init__(self, port_type, request):
self.log = Log(__name__, True)
self.request = request
self.sitecode = port_type.sitecode.upper()
self.browser_default_lang = self.request.META['HTTP_ACCEPT_LANGUAGE'].split(',')[0]
self.active_lang = self.request.session.get('lang', self.browser_default_lang.lower())
self.static_folder = 'static_%s_%s' % (self.sitecode, self.SITE_TEMPLATES_RESOURCES_SUFFIX)
self.template_path = os.path.join(settings.MEDIA_ROOT, self.static_folder)
self.template_path_port_type = '%s_%s' % (self.template_path, self.port_type.hash)
self.site_media_path = os.path.join(settings.MEDIA_URL, self.static_folder)
self.site_port_type_media_path = '%s_%s' % (self.site_media_path, self.port_type.hash)
self.site_config = SiteConfig.objects.get(sitecode=self.sitecode)
self.site = UmSite.objects.get(code=self.port_type.sitecode)
self.context = {}
I find it difficult to write unit tests for this. I should really write the tests first but somehow I ended up with this and have to refactor and am writing them now.
Use a mock request that gives you deterministic data, without connecting to the internet. For example, make a request object that returns some fixed string for request.META, and a session object that returns a fixed string for session.get(...), etc. Then assert that self.active_lang and other properties that need to be set have the right values.
Related
I have the following class:
class MessageContext:
def __init__(self, raw_packet, packet_header, message_header, message_index):
self.raw_packet = raw_packet
self.pkthdr = packet_header
self.msghdr = message_header
self.msgidx = message_index
self.msg_seqno = packet_header.seqno + message_index
And a function that creates objects using the above class:
def parsers(data):
...
context = MessageContext(None, PacketAdapter(), msghdr, 0)
self.on_message(rawmsg, context)
I am trying to recreate context, and when i set a breakpoint just after it and print context, I get:
<exchanges.protocols.blahblah.MessageContext object at 0x7337211520>
I have left out quite a bit of code as it is very long, but if any more information is needed I am happy to provide of course.
Here is what I get when I print the arguments of MessageContext:
print(PacketAdapter()) -> <exchanges.blahblah.PacketAdapter object at 0x7f60929e1820>
Following the comments below, the PacketAdapter() class looks like this:
class PacketAdapter:
def __init__(self):
self.seqno = 0
I have sample code and test:
def outer():
inner_response = inner(param1)
def inner(something):
queryset_response = something.object.filter(foo="bar",
foo1="bar1") #this should get a reponse when testing.
response_list = []
for count, queryset_res in enumerate(queryset_response):
response_list.append(queryset_response[count].data)
#get response for data in this line.
return response_list
I wanna test this situation using mock and probably return list of queryset using mock if possible.
def setup():
something = mock.Mock()
def test_outer():
# what should be done to the below line work so that
# response_list.append gets some value.
something.objects.filter()[0].data = "some string"
# Also is it possible to return queryset as like shown below.
something.objects.filter().return_value = <queryset> # list of objects in queryset.
i used a mock and returned namedtuple to make it behave like queryset and use (.) dot to access the data set. I could make a class and used it same way.
def test_func():
something = mock.Mock()
key = collections.namedtuple('key', 'data')
response = key('some_string')
something.objects.filter.return_value = [response]
this is kinda mocking django as gloo said, my ex-engineers decided to opt in that way.
You shouldn't be mocking the result of a filter as that would be like unit testing django itself. Instead, you should be testing your own functions that will call Model.object.filter. You can create the objects you will be working with in the setup of your unit test, and assert that when you call your function, the expected result is the same as those objects. For example:
def my_own_function(foo, foo1):
queryset_response = Something.objects.filter(foo=foo, foo1=foo1)
store = queryset_response[0].data
return store
and in your unit test:
def test_my_own_function():
data = "mydata"
sample_obj = Something.objects.create(foo="bar", foo1="bar1", data=data)
result = my_own_function("bar", "bar1")
self.assertEqual(result, data)
Given a class with class methods that contain only self input:
class ABC():
def __init__(self, input_dict)
self.variable_0 = input_dict['variable_0']
self.variable_1 = input_dict['variable_1']
self.variable_2 = input_dict['variable_2']
self.variable_3 = input_dict['variable_3']
def some_operation_0(self):
return self.variable_0 + self.variable_1
def some_operation_1(self):
return self.variable_2 + self.variable_3
First question: Is this very bad practice? Should I just refactor some_operation_0(self) to explicitly take the necessary inputs, some_operation_0(self, variable_0, variable_1)? If so, the testing is very straightforward.
Second question: What is the correct way to setup my unit test on the method some_operation_0(self)?
Should I setup a fixture in which I initialize input_dict, and then instantiate the class with a mock object?
#pytest.fixture
def generator_inputs():
f = open('inputs.txt', 'r')
input_dict = eval(f.read())
f.close()
mock_obj = ABC(input_dict)
def test_some_operation_0():
assert mock_obj.some_operation_0() == some_value
(I am new to both python and general unit testing...)
Those methods do take an argument: self. There is no need to mock anything. Instead, you can simply create an instance, and verify that the methods return the expected value when invoked.
For your example:
def test_abc():
a = ABC({'variable_0':0, 'variable_1':1, 'variable_2':2, 'variable_3':3))
assert a.some_operation_0() == 1
assert a.some_operation_1() == 5
If constructing an instance is very difficult, you might want to change your code so that the class can be instantiated from standard in-memory data structures (e.g. a dictionary). In that case, you could create a separate function that reads/parses data from a file and uses the "data-structure-based" __init__ method, e.g. make_abc() or a class method.
If this approach does not generalize to your real problem, you could imagine providing programmatic access to the key names or other metadata that ABC recognizes or cares about. Then, you could programmatically construct a "defaulted" instance, e.g. an instance where every value in the input dict is a default-constructed value (such as 0 for int):
class ABC():
PROPERTY_NAMES = ['variable_0', 'variable_1', 'variable_2', 'variable_3']
def __init__(self, input_dict):
# implementation omitted for brevity
pass
def some_operation_0(self):
return self.variable_0 + self.variable_1
def some_operation_1(self):
return self.variable_2 + self.variable_3
def test_abc():
a = ABC({name: 0 for name in ABC.PROPERTY_NAMES})
assert a.some_operation_0() == 0
assert a.some_operation_1() == 0
I wanted to create a proper post_create (also post_get and post_put) hooks, similar to the ones I had on the DB version of my app.
Unfortunately I can't use has_complete_key.
The problem is quite known: lack of is_saved in a model.
Right now I have implemented it like this:
class NdbStuff(HooksInterface):
def __init__(self, *args, **kwds):
super(NdbStuff, self).__init__(*args, **kwds)
self._is_saved = False
def _put_async(self, post_hooks=True, **ctx_options):
""" Implementation of pre/post create hooks. """
if not self._is_saved:
self._pre_create_hook()
fut = super(NdbStuff, self)._put_async(**ctx_options)
if not self._is_saved:
fut._immediate_callbacks.insert(
0,
(
self._post_create_hook,
[fut],
{},
)
)
self._is_saved = True
if post_hooks is False:
fut._immediate_callbacks = []
return fut
put_async = _put_async
#classmethod
def _post_get_hook(cls, key, future):
obj = future.get_result()
if obj is not None:
obj._is_saved = True
cls._post_get(key, future)
def _post_put_hook(self, future):
if future.state == future.FINISHING:
self._is_saved = True
else:
self._is_saved = False
self._post_put(future)
Everything except the post_create hook seems to work.
The post_create is triggered every time the I use put_async without retrieving the object first.
I would really appreciate a clue on how to trigger the post_create_hook only once after the object was created.
I am not sure why you are creating the NDBStuff class.
Any way if you creating an instance of a class, and you want to track _is_saved or something similar , use a factory to control creation and setting of the property, in this case it makes more sense to track _is_new for example.
class MyModel(ndb.Model):
some_prop = ndb.StringProperty()
def _pre_put_hook(self):
if getattr(self,'_is_new',None):
self._pre_create_hook()
# do something
def _pre_create_hook(self):
# do something on first save
log.info("First put for this object")
def _post_create_hook(self, future):
# do something
def _post_put_hook(self, future);
if getattr(self,'_is_new', None):
self._post_create_hook(future)
# Get rid of the flag on successful put,
# in case you make some changes and save again.
delattr(self,'_is_new')
#classmethod
def factory(cls,*args,**kwargs):
new_obj = cls(*args,**kwargs)
settattr(new_obj,'_is_new',True)
return new_obj
Then
myobj = MyModel.factory(someargs)
myobj.put()
myobj.some_prop = 'test'
myobj.put()
Will call the _pre_create_hook on the first put, and not on the second.
Always create the entities through the factory then you will always have the to call to _pre_create_hook executed.
Does that make sense ?
Hi I'm trying to tweak Python's standard unittest library to my own needs.
So far everything is experimental and I want to know if I'm doing something wrong, so here is my code:
class Should(object):
def __init__(self, subject):
self.subject = subject
self.suite = unittest.TestSuite()
def run(self):
unittest.TextTestResult().run(self.suite)
def contain(self, elem):
subject = self.subject
class Contain(unittest.TestCase):
def test_contain(self):
self.assertIn(elem, subject)
self.suite.addTest(Contain('test_contain'))
should = Should([1, 2, 3])
should.contain(1)
should.run()
If I run this piece of code I get the following error:
unittest.TextTestResult().run(self.suite)
TypeError: __init__() takes exactly 4 arguments (2 given)
According to what I've read from the unittest documentation the line unittest.TextTestResult().run(self.suite) should run the test cases on the suite.
Am I doing something wrong or it's just that the way I'm wrapping the test cases is not viable.
Thanks in advance.
When in doubt with Python, check the standard library source.
class TextTestResult(result.TestResult):
"""A test result class that can print formatted text results to a stream.
Used by TextTestRunner.
"""
separator1 = '=' * 70
separator2 = '-' * 70
def __init__(self, stream, descriptions, verbosity):
super(TextTestResult, self).__init__()
self.stream = stream
self.showAll = verbosity > 1
self.dots = verbosity == 1
self.descriptions = descriptions
So the missing parameters are descriptions and verbosity. The first is a boolean to turn on or off long descriptions of the tests, the second adjusts verbosity.
class Should(object):
def __init__(self, *subject):
self.subject = subject
self.suite = unittest.TestSuite()
def run(self):
unittest.TextTestResult().run(self.suite)
def contain(self, elem):
subject = self.subject
class Contain(unittest.TestCase):
def test_contain(self):
self.assertIn(elem, subject)
self.suite.addTest(Contain('test_contain'))
should = Should([1, 2, 3])
should.contain(1)
should.run()
Use *subject, You will not get error now.