I am testing my code in django and i have a case where i want to test if it is NOT equal. How can i do that ?
i am using the doc from django here :
https://docs.djangoproject.com/fr/2.2/topics/testing/tools/
Another example in react we have ".not" to say not equal.
I tried with '.not'
class SimpleTest(TestCase):
def test_details(self):
response = self.client.get('/customer/details/')
self.assertEqual(response.status_code, 200).not()
I expected to have one condition who test the no egality between my variable and my status code.
Thank for your help.
Solution from #DanielRoseman is working.
Used assertNotEqual fixed the problem
Doc: https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertNotEqual
Related
I'm doing a project in django and I have 2 serializer like this:
parent_serializer.py
class ParentSerializer(serializer.Serializers):
action = ChildSerializer()
child_serializer.py
class ChildSerializer(serializer.Serializers):
...
def validate(self, attrs):
...
**return attrs**
There is an if statement in the validate function and i wrote all the tests needed for the if statement, but pytest coverage keep saying that it missed the return statement line (return attrs), which imo, supposed to run in every test case.
I did try everything possible but nothing works. Please help me on that one
I found the solution.
So basically I have to cover else case in the validate function. I have a statement look like if action in: ... which actually never happened in real case, but coverage still call missing for it.
Let's say I have a Fastapi application like this (This code is taken from documentations):
app = FastAPI()
#app.get("/foo")
async def read_main():
return {"msg": "Hello World"}
I believe there are two ways of testing this view. The first one is by the use of a client object. For instance:
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
However, I think this is not a unit test. It is more like an integration test. Because we are actually running fastapi codes as well.
The second option which in my opinion is closer to unit test definition is to run the function directly:
def test_read_main():
response = read_main()
assert response == {"msg": "Hello World"}
Similarly, in Django, we can directly call the view function, or by using a client object.
My first question is which one is better?
Let's say we chose one of them and now in order to prevent calling the database I have mocked the database. Now I want to test a view that just checks if something exists in the database. My second question is what is the point of testing such view? Becuase after mocking the database, we know what would happen when calling the database with given arguments.
In setting up a ArchiveIndexView in Django I am able to successfully display a list of items in a model by navigating to the page myself.
When going to write the test in pytest to verify navigating to the page "checklist_GTD/archive/" succeeds, the test fails with the message:
> assert response.status_code == 200
E assert 301 == 200
E + where 301 = <HttpResponsePermanentRedirect status_code=301, "text/html; charset=utf-8", url="/checklist_GTD/archive/">.status_code
test_archive.py:4: AssertionError
I understand there is a way to follow the request to get the final status_code. Can someone help me with how this done in pytest-django, similar to this question? The documentation on pytest-django does not have anything on redirects. Thanks.
pytest-django provides both an unauthenticated client and a logged-in admin_client as fixtures. Really simplifies this sort of thing. Assuming for the moment that you're using admin_client because you just want to test the redirect as easily as possible, without having to log in manually:
def test_something(admin_client):
response = admin_client.get(url, follow=True)
assert response.status_code == 200
If you want to log in a standard user:
def test_something(client):
# Create user here, then:
client.login(username="foo", password="bar")
response = client.get(url, follow=True)
assert response.status_code == 200
By using follow=True in either of these, the response.status_code will equal the return code of the page after the redirect, rather than the access to the original URL. Therefore, it should resolve to 200, not 301.
I think it's not documented in pytest-django because the option is inherited from the Django test client it subclasses from (making requests).
UPDATE:
I'm getting downvoted into oblivion but I still think my answer is better so let me explain.
I still think there is a problem with Shacker's answer, where you can set follow=True and get a response code of 200 but not at the URL you expect. For example, you could get redirected unexpectedly to the login page, follow and get a response code of 200.
I understand that I asked a question on how to accomplish something with pytest and the reason I'm getting downvoted is because I provided an answer using Django's built-in TestCase class. However, the correct answer for the test is/was more important to me at the time than exclusively using pytest. As noted below, my answer still works with pytest's test discovery so I think the answer is still valid. After all, pytest is built upon Django's built-in TestCase. And my answer asserts the response code of 200 came from where I expected it to come from.
The best solution would be to modify pytest to include the expected_url as a parameter. If anyone is up for doing this I think it would be a big improvement. Thanks for reading.
ORIGINAL CONTENT:
Answering my own question here. I decided to include final expected URL using the built-in Django testing framework's assertRedirects and verify that it (1) gets redirected initially with 302 response and (2) eventually succeeds with a code 200 at the expected URL.
from django.test import TestCase, Client
def test_pytest_works():
assert 1==1
class Test(TestCase):
def test_redirect(self):
client = Client()
response = client.get("/checklist_GTD/archive/")
self.assertRedirects(response, "/expected_redirect/url", 302, 200)
Hat tip to #tdsymonds for pointing me in the right direction. I appreciated Shacker's answer but I have seen in some scenarios the redirect result being 200 when the page is redirected to an undesirable URL. With the solution above I am able to enforce the redirect URL, which pytest-django does not currently support.
Please note: This answer is compliant with the auto-discover feature of pytest-django and is thus not incompatible (it will auto-discover both pytest-django and Django TestCase tests).
I'm building unit tests for this webapp2 handler (built for GAE)
class PushNotificationHandler(webapp2.RequestHandler):
def post(self):
UserNotification.parse_from_queue(self.request)
return
app = webapp2.WSGIApplication([
(r'/push/notification', PushNotificationHandler),
], debug=True)
One test is
#patch.object(UserNotification, 'parse_from_queue')
def test_post_webapp(self, p_parse_from_queue):
response = webtest.TestApp(app).post('/push/notification')
eq_(response.status_int, 200)
p_parse_from_queue.assert_called_once_with(response.request)
The HTTP reply is OK, but the mock assertion fails:
Expected call: parse_from_queue(<TestRequest at 0x105a89850 POST http://localhost/push/notification>)
Actual call: parse_from_queue(<Request at 0x105a89950 POST http://localhost/push/notification>)
I can't understand why the request is not the correct one (looks like a deep copy). Is there anything wrong with the unit-test, or is that the way webapp2 handle requests. In the second case, is there a way to test it, without creating a separate test to test PushNotificationHandler.post()
Thanks
I've used mock's call_args in a similar situation. You can do something like this:
request = p_parse_from_queue.call_args[0][0]
self.assertEqual(request.url, "foo")
self.assertEqual(request.*, *)
The [0][0] gives you the first passed argument assuming that you are using ordered arguments and not keyword arguments.
You can then proceed to check other relevant attributes of the request object to make sure it is behaving as expected.
I have been exploring mock and pytest for a few days now.
I have the following method:
def func():
if not os.path.isdir('/tmp/folder'):
os.makedirs('/tmp/folder')
In order to unit test it, I have decided to patch os.path.isdir and os.makedirs, as shown:
#patch('os.path.isdir')
#patch('os.makedirs')
def test_func(patch_makedirs, patch_isdir):
patch_isdir.return_value = False
assert patch_makedirs.called == True
The assertion fails, irrespective of the return value from patch_isdir. Can someone please help me figure out where I am going wrong?
Can't say for sure having the complete code, but I have the feeling it's related to where you're patching.
You should patch the os module that was imported by the module under test.
So, if you have it like this:
mymodule.py:
def func():
if not os.path.isdir('/tmp/folder'):
os.makedirs('/tmp/folder')
you should make your _test_mymodule.py_ like this:
#patch('mymodule.os')
def test_func(self, os_mock):
os_mock.path.isdir.return_value = False
assert os_mock.makedirs.called
Note that this specific test is not that useful, since it's essentially testing if the module os works -- and you can probably assume that is well tested. ;)
Your tests would probably be better if focused on your application logic (maybe, the code that calls func?).
You are missing the call to func().
#patch('os.path.isdir')
#patch('os.makedirs')
def test_func(patch_makedirs, patch_isdir):
patch_isdir.return_value = False
yourmodule.func()
assert patch_makedirs.called == True