I want to test
if a views decorator works properly
if a proper view is called
So, here's decorator get_object and view features are in myapp.views.
#get_object
def features(request, object):
return {}
I try mocking this:
new_view = Mock(__name__='features', return_value={})
decorated = get_object(new_view)
with patch('myapp.views.features') as features:
features = decorated
client = Client()
response = client.get('/features')
print new_view.call_args
This shows nothing, as if the mock object was not called, although I suppose it should have been.
How can I mock the decorated view properly?
When you call patch you are replacing your view with a brand new MagicMock. Since you are manually constructing a mock for you view you should do something more like (untested):
new_view = Mock(__name__='features', return_value={})
features = get_object(new_view)
with patch('myapp.views.features', features):
client = Client()
response = client.get('/features')
print new_view.call_args
This will replace myapp.views.features with your hand rolled mock.
In general though I would recommend that you test your decorator in isolation without using the Django test client. Your really mixing two tests into one here. The first is making sure the decorator does it's duty and the other is making sure the request is properly routed.
Related
I want to write a mock for a library object without inheriting from it in order to properly test, however without having to stub all non used functions of the original object.
To be specific I want to write a ContextMock for the invoke library.
class ContextMock:
...
The main problem here is that I therefor call a #task function which then calls my code that I want to test. However the #task decorator checks whether the context object is an instance of a Context, like this:
def __call__(self, *args, **kwargs):
# Guard against calling tasks with no context.
if not isinstance(args[0], Context):
err = "Task expected a Context as its first arg, got {} instead!"
# TODO: raise a custom subclass _of_ TypeError instead
raise TypeError(err.format(type(args[0])))
Therefor my question is, can I somehow change the isinstance function of my ContextMock, or make it look like its an instance of Context without inheriting its attributes?
Or would it be possible to somehow mock the isinstance function?
How does the default implementation of instancecheck work? Is there perhabs a baseclass attribute that can be overwritten?
I already tried to provide a custom metaclass with an custom instancecheck function, which of course does not work as the instancecheck of the Context is called, right?
Also Note that I'm well aware that any hacky solution should not belong in production code, and is only used for testing.
Edit:
To add a generic example of what I want to archive:
class Context:
pass
class ContextMock:
pass
mock = ContextMock
... do magic with mock
assert isinstance(mock, Context)
I am struggling to understand when it makes sense to use an instance method versus a static method. Also, I don't know if my functions are static since there is not a #staticmethod decorator. Would I be able to access the class functions when I make a call to one of the methods?
I am working on a webscraper that sends information to a database. It’s setup to run once a week. The structure of my code looks like this
import libraries...
class Get:
def build_url(url_paramater1, url_parameter2, request_date):
return url_with_parameters
def web_data(request_date, url_parameter1, url_parameter2): #no use of self
# using parameters pull the variables to look up in the database
for a in db_info:
url = build_url(a, url_parameter2, request_date)
x = requests.Session().get(url, proxies).json()
#save data to the database
return None
#same type of function for pulling the web data from the database and parsing it
if __name__ == ‘__main__’:
Get.web_data(request_date, url_parameter1, url_parameter2)
Parse.web_data(get_date, parameter) #to illustrate the second part of the scrapper
That is the basic structure. The code is functional but I don’t know if I am using the methods (functions?) correctly and potentially missing out on ways to use my code in the future. I may even be writing bad code that will cause errors down the line that are impossibly hard to debug only because I didn’t follow best practices.
After reading about when class and instance methods are used. I cannot see why I would use them. If I want the url built or the data pulled from the website I call the build_url or get_web_data function. I don’t need an instance of the function to keep track of anything separate. I cannot imagine when I would need to keep something separate either which I think is part of the problem.
The reason I think my question is different than the previous questions is: the conceptual examples to explain the differences don't seem to help me when I am sitting down and writing code. I have not run into real world problems that are solved with the different methods that show when I should even use an instance method, yet instance methods seem to be mandatory when looking at conceptual examples of code.
Thank you!
Classes can be used to represent objects, and also to group functions under a common namespace.
When a class represents an object, like a cat, anything that this object 'can do', logically, should be an instance method, such as meowing.
But when you have a group of static functions that are all related to each other or are usually used together to achieve a common goal, like build_url and web_data, you can make your code clearer and more organized by putting them under a static class, which provides a common namespace, like you did.
Therefore in my opinion the structure you chose is legitimate. It is worth considering though, that you'd find static classes more in more definitively OOP languages, like Java, while in python it is more common to use modules for namespace separation.
This code doesn't need to be a class at all. It should just be a pair of functions. You can't see why you would need an instance method because you don't have a reason to instantiate the object in the first place.
The functions you have wrote in your code are instance methods but they were written incorrectly.
An instance method must have self as first parameter
i.e def build_url(self, url_paramater1, url_parameter2, request_date):
Then you call it like that
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
This self parameter is provided by python and it allow you to access all properties and functions - static or not - of your Get class.
If you don't need to access other functions or properties in your class then you add #staticmethod decorator and remove self parameter
#staticmethod
def build_url(url_paramater1, url_parameter2, request_date):
And then you can call it directly
Get.build_url(url_paramater1, url_parameter2, request_date)
or call from from class instance
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
But what is the problem with your current code you might ask?
Try calling it from an instance like this and u will see the problem
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
Example where creating an instance is useful:
Let's say you want to make a chat client.
You could write code like this
class Chat:
def send(server_url, message):
connection = connect(server_url)
connection.write(message)
connection.close()
def read(server_url):
connection = connect(server_url)
message = connection.read()
connection.close()
return message
But a much cleaner and better way to do it:
class Chat:
def __init__(server_url):
# Initialize connection only once when instance is created
self.connection = connect(server_url)
def __del__()
# Close connection only once when instance is deleted
self.connection.close()
def send(self, message):
self.connection.write(message)
def read(self):
return self.connection.read()
To use that last class you do
# Create new instance and pass server_url as argument
chat = Chat("http://example.com/chat")
chat.send("Hello")
chat.read()
# deleting chat causes __del__ function to be called and connection be closed
delete chat
From given example, there is no need to have Get class after all, since you are using it just like a additional namespace. You do not have any 'state' that you want to preserve, in either class or class instance.
What seems like a good thing is to have separate module and define these functions in it. This way, when importing this module, you get to have this namespace that you want.
I have a class with a dictionary that is used to cache response from server for a particular input. Since this is used for caching purpose, this is kept as a class variable.
class MyClass:
cache_dict = {}
def get_info_server(self, arg):
if arg not in self.cache_dict:
self.cache_dict[arg] = Client.get_from_server(arg)
return cache_dict[arg]
def do_something(self, arg):
# Do something based on get_info_server(arg)
And when writing unit tests, since the dictionary is a class variable, the values are cached across test cases.
Test Cases
# Assume that Client is mocked.
def test_caching():
m = MyClass()
m.get_info_server('foo')
m.get_info_server('foo')
mock_client.get_from_server.assert_called_with_once('foo')
def test_do_something():
m = MyClass()
mock_client.get_from_server.return_value = 'bar'
m.do_something('foo') # This internally calls get_info_server('foo')
If test_caching executes first, the cached value will be some mock object. If test_do_something executes first, then the assertion that the test case is called exactly once will fail.
How do I make the tests independent of each other, besides manipulating the dictionary directly (since this is like requiring intimate knowledge of the inner working of the code. what if the inner working were to change later. All I need to verify is the API itself, and not rely on the inner workings)?
You can't really avoid resetting your cache here. If you are unittesting this class, then your unittest will need to have an intimate knowledge of the inner workings of the class, so just reset the cache. You rarely can change how your class works without adjusting your unittests anyway.
If you feel that that still will create a maintenance burden, then make cache handling explicit by adding a class method:
class MyClass:
cache_dict = {}
#classmethod
def _clear_cache(cls):
# for testing only, hook to clear the class-level cache.
cls.cache_dict.clear()
Note that I still gave it a name with a leading underscore; this is not a method that a 3rd party should call, it is only there for tests. But now you have centralised clearing the cache, giving you control over how it is implemented.
If you are using the unittest framework to run your tests, clear the cache before each test in a TestCase.setUp() method. If you are using a different testing framework, that framework will have a similar hook. Clearing the cache before each test ensures that you always have a clean state.
Do take into account that your cache is not thread safe, if you are running tests in parallel with threading you'll have issues here. Since this also applies to the cache implementation itself, this is probably not something you are worried about right now.
You didn't put it in the question explicitly, but I'm assuming your test methods are in a subclass of unittest.TestCase called MyClassTests.
Explicitly set MyClass.cache_dict in the method under test. If it's just a dictionary, without any getters / setters for it, you don't need a Mock.
If you want to guarantee that every test method is independent, set MyClass.cache_dict = {} in MyClassTests.setup().
You need to make use of Python's built in UnitTest TestCase and implement setup and teardown methods.
If you define setUp() and tearDown() in your tests, these will execute each time one of the single test methods gets called (before and after, respectively)
Example:
# set up any global, consistent state here
# subclass unit test test case here.
def setUp(self):
# prepare your state if needed for each test, if this is not considered "fiddling", use this method to set your cache to a fresh state each time
your_cache_dict_variable = {}
### Your test methods here
def tearDown(self):
# this will handle resetting the state, as needed
Check out the docs for more info: https://docs.python.org/2/library/unittest.html
One thing I can suggest is to use setUp() and tearDown() methods in your test class.
from unittest import TestCase
class MyTest(TestCase):
def setUp(self):
self.m = MyClass()
//anything else you need to load before testing
def tearDown(self):
self.m = None
def test_caching(self):
self.m.get_info_server('foo')
self.m.get_info_server('foo')
mock_client.get_from_server.assert_called_with_once('foo')
I would like to create a mock.Mock() object, then add a method called session that acts like an instance method, which is passed a self reference to the mock object, allowing the method to add state to the mock object. Is this possible (without manually using types.MethodType, e.g., using mock's built-in API), or should I just find a way around it?
Note, I found this question, which is for Ruby and seems to cover something similar, if not the same thing. Unfortunately, I don't know Ruby very well at all.
mock_answer = Mock()
def session():
mock_answer.b = 1
mock_answer.session = session
mock_answer.session()
print(mock_answer.b) # 1
You don't need self actually.
If you want to enhance the capabilities of the mock.Mock class, just subclass Mock and add your own methods.
class MyMock(Mock):
def session(self):
# Save session data here?
The mock documentation explains that when a new mock is to be created, it will be the same type as the parent. This means that the session function will also be available on any other mocks which are created during mocking.
This doesn't cover the case where you need to dynamically attach a session function to an existing mock object.
I have django code that interacts with request objects or user objects. For instance something like:
foo_model_instance = models.get_or_create_foo_from_user(request.user)
If you were going to test with the django python shell or in a unittest, what would you pass in there? Here simply a User object will do, but the need for a mock request object also comes up frequently.
For the shell or for unittests:
How do you mock users?
How do you mock requests?
For request, I would use RequestFactory included with Django.
from django.test.client import RequestFactory
rf = RequestFactory()
get_request = rf.get('/hello/')
post_request = rf.post('/submit/', {'foo': 'bar'})
for users, I would use django.contrib.auth.models.User as #ozan suggested and maybe with factory boy for speed (with factory boy you can choose to not to save to DB)
How do you mock users?
Initialise a django.contrib.auth.models.User object. User.objects.create_user makes this easy.
How do you mock requests?
Initialise a django.http.HttpRequest object.
Of course, there are shortcuts depending on what you want to do. If you just need an object with a user attribute that points to a user, simply create something (anything) and give it that attribute.
You can either roll your own mocks, as Anurag Uniyal has suggested, or you can use a mocking framework.
In response to those saying you can just create an ordinary user as you would anyway in Django... I would suggest this defeats the point of the unit test. A unit test shouldn't touch the database, but by creating a user, you've changed the database, hence why we would want to mock one.
You don't need to mock Users, as you can just create one within your test - the database is destroyed after the test is finished.
To mock requests, use this snippet from Simon Willison.
Read about mock objects here
http://en.wikipedia.org/wiki/Mock_object
http://www.mockobjects.com/
And use this python lib to mock a user
http://python-mock.sourceforge.net/
else you can write a simple User class yourself, use this as a starting point
class MockUser(object):
def __call__(self, *args, **kwargs):
return self
def __getattr__(Self, name):
return self
add specfic cases etc etc
There are already a lot of good general answers. Here is a simple mock user used in tests involving admin forms:
class MockUser:
is_active = True
is_staff = True
def has_perm(self, *args):
return True
from django.test.client import RequestFactory
request = RequestFactory().get("/some/url")
request.user = MockUser()