I'm writing tests for a Django application and using a attribute on my test class to store which view it's supposed to be testing, like this:
# IN TESTS.PY
class OrderTests(TestCase, ShopTest):
_VIEW = views.order
def test_gateway_answer(self):
url = 'whatever url'
request = self.request_factory(url, 'GET')
self._VIEW(request, **{'sku': order.sku})
# IN VIEWS.PY
def order(request, sku)
...
My guess is that the problem I'm having is caused because since I'm calling an attribute of the OrderTests class, python assumes I wanna send self and then order get the wrong arguments. Easy to solve... just not use it as a class attribute, but I was wondering if there's a way to tell python to not send self in this case.
Thanks.
This happens because in Python functions are descriptors, so when they are accessed on class instances they bind their first (assumed self) parameter to the instance.
You could access _VIEW on the class, not on the instance:
class OrderTests(TestCase, ShopTest):
_VIEW = views.order
def test_gateway_answer(self):
url = 'whatever url'
request = self.request_factory(url, 'GET')
OrderTests._VIEW(request, **{'sku': order.sku})
Alternatively, you can wrap it in staticmethod to prevent it being bound to the instance:
class OrderTests(TestCase, ShopTest):
_VIEW = staticmethod(views.order)
def test_gateway_answer(self):
url = 'whatever url'
request = self.request_factory(url, 'GET')
self._VIEW(request, **{'sku': order.sku})
Related
im working on a python package and I wonder how can I declare a class, which receive some attributes in the init function and then be able to use that 'self' attributes in the rest of the functions without declaring self as it's parameters.
Here is an example code to make it easier:
class API():
def __init__(self, token):
self.token = token
def info():
headers = {'Token': f'{self.token}'}
response = requests.post(some_url, headers=headers)
return response
I didn't put self in info() function because that function is going to be called from the outside, but it will be great be able to reuse the token attribute received in the class initialization. i don't know if I'm missing something so any suggestion will be much appreciated.
Edit
If I use my current code, I get an error because using self keyword without declaring it on the function class, but if I put it, then when I make the function call I can pass self argument.
self is not a keyword; it's just a conventional name for the instance of API that is passed to info when it is called as an instance method.
You can't call info without such an instance.
class API():
def __init__(self, token):
self.token = token
def info(self):
headers = {'Token': f'{self.token}'}
response = requests.post(some_url, headers=headers)
return response
a = API("some token")
a.info()
a.info() is roughly equivalent to API.info(a).
I have the following code:
class Messenger(object):
def __init__(self):
# Class Type of what messages will be created as.
message_class = Message
def publish(self, body):
# Instantiate object of type stored in `message_class`
message = message_class(body)
message.publish()
I want to assert that the Message.publish() method is called. How do I achieve this?
I've already tried the following ways:
Assign message_class to Mock or Mock(). If I debug what message_class(body) returns, it is a Mock, but I don't seem to be able to get the instance and assert it (because the Mock I assign in my test is not the instance used, it is the Type).
Patch Message class with decorator. Whenever I do this it seems like it does not catch it. When I debug what message_class(body) returns its of Message type, not Mock.
Try to mock the __init__ method of message_class in hopes that I can set the instance that is returned whenever the code tries to Instantiate the message. Does not work, throws errors because the __init__ method is not suppose to have a return value.
If you were storing the actual instance, I'd say you could do something like messenger.message.publish.assert_called_once, but since message_class is being stored, it makes it slightly trickier. Given that, you can pull the return_value from the mocked class and check the call that way. Here's how I did it:
Messenger. Note the slight modification to assign message_class to self. I'm assuming you meant to do that, otherwise it wouldn't work without some global funkiness:
'''messenger.py'''
class Message(object):
def __init__(self, body):
self.body = body
def publish(self):
print('message published: {}'.format(self.body))
class Messenger(object):
def __init__(self):
# Class Type of what messages will be created as.
self.message_class = Message
def publish(self, body):
# Instantiate object of type stored in `message_class`
message = self.message_class(body)
message.publish()
Test:
'''test_messenger.py'''
from unittest import mock, TestCase
from messenger import Messenger
class TestMessenger(TestCase):
#mock.patch('messenger.Message')
def test_publish(self, mock_message):
messenger = Messenger()
messenger.publish('test body')
# .return_value gives the mock instance, from there you can make your assertions
mock_message.return_value.publish.assert_called_once()
I wanted to get the values of self.request.get('foo') and etal everytime I create an instance of a class, so I decided to use __init__ constructor. Here's my code:
class archive(handler):
d = dict(title='',author= '')
def __init__(self):
self.d['title'] = self.request.get('title')
self.d['author'] = self.request.get('author')
class compose(handler):
def get(self):
self.render('compose.html')
def post(self):
a = archive()
My purpose is, to get rid the repetition of:
title = self.request.get('title')
author = self.request.get('author')
in every def post(self). But the problem is I get a NoneType error:
AttributeError: 'NoneType' object has no attribute 'get'
Obviously, self.request.get('title') returned None. I am just new with Python and Google Appengine.
Thank you guys.
This is how I managed to fix the problem:
class Archive(object):
d = dict(title='',author= '')
def load_d(self):
r = webapp2.get_request()
self.d['title'] = r.get('title')
self.d['author'] = r.get('author')
class Compose(Handler):
def get(self):
self.render('compose.html')
def post(self):
a = Archive()
a.load_d()
I assume you use webapp2.
Your init overrides the init of the webapp2 request handler (super). You can read in the webapp2 docs how to to this:
http://webapp-improved.appspot.com/guide/handlers.html#overriding-init
Take care when you use variables (self.variable) because you can also override variables of the request handler. You can use the request registry.
I've got:
class ArticleController(SubbaseController):
def view(self):
c.referral = self.detect_referral.referrer
return render('/article.mako')
#staticmethod
def detect_referral():
referrer = request.META.get('HTTP_REFERRER', '')
I'm trying to reference the referrer inside of the view action from the detect_referral static method, but I keep getting: 'function' object has no attribute 'referrer' instead. Any ideas?
Also, is that the correct way to get the referrer?
You aren't returning the referrer from detect_referral, and detect_referral is not a property, so you cannot use that syntax.
class ArticleController(BaseController):
def view(self):
c.referral = self.detect_referral()
return render('/article.mako')
#staticmethod
def detect_referral():
return request.META.get('HTTP_REFERRER', '')
It's a local variable inside detect_referral(), and as such its lifetime is limited to the execution time of the method. Before the method is called and after the method returns local variables simply don't exist. (You don't even seem to call the method, so the local variable exists at no time of the execution of your program.)
Most probably you don't want a static method here. (You almost never want a static method in Python. I cannot remember that I ever used one.) Maybe all you need is a class attribute:
class ArticleController(SubbaseController):
referrer = request.META.get('HTTP_REFERRER', '')
def view(self):
c.referral = self.referrer
return render('/article.mako')
Note that the class body is executed once at class definition time.
I want to achieve maximum testability in my Google App Engine app which I'm writing in Python.
Basically what I'm doing is creating an all-purpose base handler which inherits the google.appengine.ext.webapp.RequestHandler. My base handler will expose common functionality in my app such as repository functions, a session object and the like.
When the WSGIApplication receives a request it will find the handler class that has been registered for the requested URL, and call its constructor and after that it will call a method called initialize passing in the request and response objects.
Now, for the sake of testability I want to be able to "mock" these objects (along with my own objects). So my question is how do I go about injecting these mocks? I can override the initialize method in my base handler and check for some global "test flag" and initialize some dummy request and response objects. But it seems wrong (in my mind at least). And how do I go about initializing my other objects (which may depend on the request and response objects)?
As you can probably tell I'm a little new to Python so any recommendations would be most welcome.
EDIT:
It has been pointed out to me that this question was a little hard to answer without some code, so here goes:
from google.appengine.ext import webapp
from ..utils import gmemsess
from .. import errors
_user_id_name = 'userid'
class Handler(webapp.RequestHandler):
'''
classdocs
'''
def __init__(self):
'''
Constructor
'''
self.charset = 'utf8'
self._session = None
def _getsession(self):
if not self._session:
self._session = gmemsess.Session(self)
return self._session
def _get_is_logged_in(self):
return self.session.has_key(_user_id_name)
def _get_user_id(self):
if not self.is_logged_in:
raise errors.UserNotLoggedInError()
return self.session[_user_id_name]
session = property(_getsession)
is_logged_in = property(_get_is_logged_in)
user_id = property(_get_user_id)
As you can see, no dependency injection is going on here at all. The session object is created by calling gmemsess.Session(self). The Session class expects a class which has a request object on it (it uses this to read a cookie value). In this case, self does have such a property since it inherits from webapp.RequestHandler. It also only has the object on it because after calling (the empty) constructor, WSGIApplication calls a method called initialize which sets this object (and the response object). The initialize method is declared on the base class (webapp.RequestHandler).
It looks like this:
def initialize(self, request, response):
"""Initializes this request handler with the given Request and
Response."""
self.request = request
self.response = response
When a request is made, the WSGIApplication class does the following:
def __call__(self, environ, start_response):
"""Called by WSGI when a request comes in."""
request = self.REQUEST_CLASS(environ)
response = self.RESPONSE_CLASS()
WSGIApplication.active_instance = self
handler = None
groups = ()
for regexp, handler_class in self._url_mapping:
match = regexp.match(request.path)
if match:
handler = handler_class()
handler.initialize(request, response)
groups = match.groups()
break
self.current_request_args = groups
if handler:
try:
method = environ['REQUEST_METHOD']
if method == 'GET':
handler.get(*groups)
elif method == 'POST':
handler.post(*groups)
'''SNIP'''
The lines of interest are those that say:
handler = handler_class()
handler.initialize(request, response)
As you can see, it calls the empty constructor on my handler class. And this is a problem for me, because what I think I would like to do is to inject, at runtime, the type of my session object, such that my class would look like this instead (fragment showed):
def __init__(self, session_type):
'''
Constructor
'''
self.charset = 'utf8'
self._session = None
self._session_type = session_type
def _getsession(self):
if not self._session:
self._session = self._session_type(self)
return self._session
However I can't get my head around how I would achieve this, since the WSGIApplication only calls the empty constructor. I guess I could register the session_type in some global variable, but that does not really follow the philosophy of dependency injection (as I understand it), but as stated I'm new to Python, so maybe I'm just thinking about it the wrong way. In any event I would rather pass in a session object instead of it's type, but this looks kind of impossible here.
Any input is appreciated.
The simplest way to achieve what you want would be to create a module-level variable containing the class of the session to create:
# myhandler.py
session_class = gmemsess.Session
class Handler(webapp.Request
def _getsession(self):
if not self._session:
self._session = session_class(self)
return self._session
then, wherever it is that you decide between testing and running:
import myhandler
if testing:
myhandler.session_class = MyTestingSession
This leaves your handler class nearly untouched, leaves the WSGIApplication completely untouched, and gives you the flexibility to do your testing as you want.
Why not just test your handlers in isolation? That is, create your mock Request and Response objects, instantiate the handler you want to test, and call handler.initialize(request, response) with your mocks. There's no need for dependency injection here.