for loop in django unittest - django

I want to test register view in django project,
so I build some fake test cases(self.correct_samples)
after register successfully, it should redirect to home page which means the status code should be 302.
from django.test import TestCase
from django.urls.base import reverse
class RegisterTests(TestCase):
def setUp(self):
url = reverse('account:register')
self.response = self.client.get(url)
self.correct_samples = (
('testuser1#email.com', 'testuser', 'test112233', 'test112233'),
('fakeuser#email.com', 'fake123', 'fakeuser111', 'fakeuser111'),
('correct#email.com', 'Jack', 'myfavorite', 'myfavorite'),
('failemail', 'Jack', 'myfavorite', 'myfavorite'), # fail for purpose
)
def test_register_form(self):
for test_case in self.correct_samples:
email, username, password1, password2 = test_case
self.response = self.client.post(reverse('account:register'), data={
'email': email,
'username': username,
'password1': password1,
'password2': password2,
})
self.assertEqual(self.response.status_code, 302)
self.assertRedirects(
self.response, expected_url='/', status_code=302, target_status_code=200)
The fourth data in self.correct_samples which is ('failemail', 'Jack', 'myfavorite', 'myfavorite') should be a fail case.
but after python manage.py test. It passed.
(env) C:\Users\User\myblog>python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
C:\Users\User\myblog\env\lib\site-packages\whitenoise\base.py:115: UserWarning: No directory at: C:\Users\User\myblog\staticfiles\
warnings.warn(u"No directory at: {}".format(root))
.
----------------------------------------------------------------------
Ran 1 test in 0.195s
OK
Destroying test database for alias 'default'...
Here comes the tricky thing,
it failed after switching order from fourth to first.
from django.test import TestCase
from django.urls.base import reverse
class RegisterTests(TestCase):
def setUp(self):
...
self.correct_samples = (
('failemail', 'Jack', 'myfavorite', 'myfavorite'), # fail for purpose
('testuser1#email.com', 'testuser', 'test112233', 'test112233'),
('fakeuser#email.com', 'fake123', 'fakeuser111', 'fakeuser111'),
('correct#email.com', 'Jack', 'myfavorite', 'myfavorite'),
)
def test_register_form(self):
...
result:
(env) C:\Users\User\myblog>python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
C:\Users\User\myblog\env\lib\site-packages\whitenoise\base.py:115: UserWarning: No directory at: C:\Users\User\myblog\staticfiles\
warnings.warn(u"No directory at: {}".format(root))
F
======================================================================
FAIL: test_register_form (account.tests.RegisterTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\User\myblog\account\tests.py", line 34, in test_register_form
self.assertEqual(self.response.status_code, 302)
AssertionError: 200 != 302
----------------------------------------------------------------------
Ran 1 test in 0.026s
FAILED (failures=1)
Destroying test database for alias 'default'...
Why this happened?
I have searched for related keywords like unittest in forloop, multiple testcases in forloop.
but it seems no answers for it, or maybe search through other keywords?
or something I missed or misunderstood?
thanks for helping.

Problem has been solved!
According to this questions How do you generate dynamic (parameterized) unit tests in Python?
Solution: parameterized

Related

Django TestCase using self.client.post() is sending a GET resquest

I'm creating a integration Test Class. The self.client.get is working fine, but self.client.post is sending GET and I'm receiving a [httpResponse("Method Not Allowed", 405)].
from django.test import TestCase
import json
class Test_Integration(TestCase):
def test_create_exist_product(self):
response = self.client.post('http://127.0.0.1:8201/v1/products/create', {"name": "product7", "latest_version": "0"}, follow=True, secure=False)
print(response)
self.assertEqual(response, "Product name already exists")
Function
def create_product(request):
logger.info("Entering function create_product..")
logger.info("REQUEST TYPE: "+str(request.method))
if request.method == "POST":
CODE HERE
return HttpResponse("Method Not Allowed", 405)
Log errors:
Found 4 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
INFO 2022-11-16 13:45:12,066 views 13612 19052 Entering function create_product..
INFO 2022-11-16 13:45:12,068 views 13612 19052 REQUEST TYPE: GET
<HttpResponse status_code=200, "405">
======================================================================
FAIL: test_create_exist_product (project.Tests.test_integration.Test_Integration)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\backend\project\Tests\test_integration.py", line 23, in test_create_exist_product
self.assertEqual(response, "Product name already exists")
AssertionError: <HttpResponse status_code=200, "405"> != 'Product name already exists'
----------------------------------------------------------------------
Ran 4 tests in 6.523s
FAILED (failures=1)
Destroying test database for alias 'default'...

django test client returns 404, but works in the shell

This code works fine in the shell, but if you run it through python manage.py test it throws a 404 error, what could be the problem?
test_urls.py
from django.test import Client, TestCase
class StaticURLTests(TestCase):
def setUp(self):
self.guest_client = Client()
def test_homepage(self):
response = self.guest_client.get("/")
self.assertEqual(response.status_code, 200)
error:
❯ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_homepage (posts.tests.test_urls.StaticURLTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/finegorko/Development/Yandex.Practicum/hw03_forms/yatube/posts/tests/test_urls.py", line 10, in test_homepage
self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
Destroying test database for alias 'default'...
The problem was that a test database was being created that did not have a group.
In views.py an object with the function get_object_or_404() was passed to the index context.
def index(request):
...
group = get_object_or_404(Group) # <--

reliably kill phantomjs launched in setUpClass if derived class' setUpClass fails

I wrote a SeleniumTestCase class that launches PhantomJS in its setUpClass and kills it in its tearDownClass. However, if a derived class' setUpClass raises an error, the PhantomJS process is left hanging because SeleniumTestCase.tearDownClass doesn't get called.
from django.test import LiveServerTestCase
import sys, signal, os
from selenium import webdriver
errorShots = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', "errorShots")
class SeleniumTestCase(LiveServerTestCase):
#classmethod
def setUpClass(cls):
"""
Launches PhantomJS
"""
super(SeleniumTestCase, cls).setUpClass()
cls.browser = webdriver.PhantomJS()
#classmethod
def tearDownClass(cls):
"""
Saves a screenshot if the test failed, and kills PhantomJS
"""
print 'Tearing down...'
if cls.browser:
if sys.exc_info()[0]:
try:
os.mkdir(errorShots)
except:
pass
errorShotPath = os.path.join(
errorShots,
"ERROR_phantomjs_%s_%s.png" % (cls._testMethodName, datetime.datetime.now().isoformat())
)
cls.browser.save_screenshot(errorShotPath)
print 'Saved screenshot to', errorShotPath
cls.browser.service.process.send_signal(signal.SIGTERM)
cls.browser.quit()
class SetUpClassTest(SeleniumTestCase):
#classmethod
def setUpClass(cls):
print 'Setting Up'
super(SetUpClassTest, cls).setUpClass()
raise Error('gotcha!')
def test1(self):
pass
Output (note that "Tearing Down" doesn't get printed)
$ ./manage.py test
Creating test database for alias 'default'...
Setting Up
E
======================================================================
ERROR: setUpClass (trucks.tests.SetUpClassTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/andy/leased-on/trucks/tests.py", line 1416, in setUpClass
raise Error('gotcha!')
NameError: global name 'Error' is not defined
----------------------------------------------------------------------
Ran 0 tests in 1.034s
FAILED (errors=1)
Destroying test database for alias 'default'...
How can I kill PhantomJS after a suite's setUpClass fails?
I know I could switch to using setUp and addCleanup, but I want to avoid relaunching PhantomJS (and logging back into my app with it) before every single test.
I decided to use setUpModule and tearDownModule to launch and kill PhantomJS. I put the screenshot-saving code in an addCleanup hook.
from django.test import LiveServerTestCase
from selenium import webdriver
import sys
import signal
import os
import unittest
errorShots = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', "errorShots")
browser = None
def setUpModule():
"""
Launches PhantomJS
"""
global browser
sys.stdout.write('Starting PhantomJS...')
sys.stdout.flush()
browser = webdriver.PhantomJS()
print 'done'
def tearDownModule():
"""
kills PhantomJS
"""
if browser:
sys.stdout.write('Killing PhantomJS...')
sys.stdout.flush()
browser.service.process.send_signal(signal.SIGTERM)
browser.quit()
print 'done'
class SeleniumTestCase(LiveServerTestCase):
def setUp(self):
self.addCleanup(self.cleanup)
def cleanup(self):
"""
Saves a screenshot if the test failed
"""
if sys.exc_info()[0]:
try:
os.mkdir(errorShots)
except:
pass
errorShotPath = os.path.join(
errorShots,
"ERROR_phantomjs_%s_%s.png" % (self._testMethodName, datetime.datetime.now().isoformat())
)
browser.save_screenshot(errorShotPath)
print '\nSaved screenshot to', errorShotPath

No forms exist in unit test with django-webtest

I want to write a test that will test change the password in the application. I use the django-allauth. For testing, I use django-WebTest.
When I run my code, I get the message:
FAILED (errors=1)
Destroying test database for alias 'default'...
mark#mariusz-K73E:~/myapp$ python manage.py test users
Creating test database for alias 'default'...
.E
======================================================================
ERROR: test_password_change_use_template (myapp.users.tests.ChangePasswordTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/mark/myapp/users/tests.py", line 16, in test_password_change_use_template
password_change.form['oldpassword'] = "test123"
File "/home/mark/.virtualenvs/urlop/local/lib/python2.7/site-packages/webtest/response.py", line 56, in form
"You used response.form, but no forms exist")
TypeError: You used response.form, but no forms exist
My code:
from django_webtest import WebTest
from django_dynamic_fixture import G
from users.models import User
from django.core.urlresolvers import reverse
class ChangePasswordTest(WebTest):
def setUp(self):
self.user = G(User)
def test_password_change_code(self):
password_change = self.app.get(reverse('account_change_password'), user=self.user)
def test_password_change_use_template(self):
password_change = self.app.get(reverse('account_change_password'), user=self.user)
password_change.form['oldpassword'] = "test123"
password_change.form['password1'] = "test456"
password_change.form['password2'] = "test456"
password_change.form.submit()
self.assertRedirects(password_change, reverse('change_password'))
WebTest tests the rendered content. There is no form found in the HTML (maybe the form tag is incorrect or missing).
If it's working in your manual test. You can try to print the response to see what's different:
def test_password_change_use_template(self):
response = self.app.get(reverse('account_change_password'), user=self.user)
print response

How to test 404 NOT FOUND with django testing framework?

I am trying to automate 404 pages testing using Django 1.4's testing framework.
If I print 127.0.0.1:8000/something/really/weird/ in browser address bar with development server running, I see a 404 page, with correct "404 NOT FOUND" status (as firebug shows).
But if I try to use this code for testing:
from django.test import TestCase
class Sample404TestCase(TestCase):
def test_wrong_uri_returns_404(self):
response = self.client.get('something/really/weird/')
self.assertEqual(response.status_code, 404)
the test fails with this output:
$./manage.py test main
Creating test database for alias 'default'...
.F
======================================================================
FAIL: test_wrong_uri_returns_404 (main.tests.Sample404TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File ".../main/tests.py", line 12, in test_wrong_uri_returns_404
self.assertEqual(response.status_code, 404)
*AssertionError: 200 != 404*
----------------------------------------------------------------------
Ran 2 tests in 0.031s
FAILED (failures=1)
Destroying test database for alias 'default'...
I'm seriously surprised with getting 200 code here. Anyone have any idea why on earth this is happening?
updated:
here lies urls.py: http://pastebin.com/DikAVa8T
and actual failing test is:
def test_wrong_uri_returns_404(self):
response = self.client.get('/something/really/weird/')
self.assertEqual(response.status_code, 404)
everything is happening in project https://github.com/gbezyuk/django-app-skeleton
Try
response = self.client.get('/something/really/weird/') # note the '/' before something
127.0.0.1:8000/something/really/weird/ is /something/really/weird/ in path relative to root, not
something/really/weird
something/really/weird/
/something/really/weird
The problem is that your ViewFor404 class returns a 200 status code. Look at Django's TemplateView definition:
class TemplateView(TemplateResponseMixin, View):
"""
A view that renders a template.
"""
def get_context_data(self, **kwargs):
return {
'params': kwargs
}
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
so all your class does is a render_to_response, which generates a '200' response.
If you need to override the 404 handler, you should do something more like this in the view:
return HttpResponseNotFound('<h1>Page not found</h1>')
(I don't know the equivalent in class-based views)
Or better yet, can you avoid customizing the View? To customize the 404 display, you can just create a 404.html template (in your site's templates/ directory), and it will be picked up by Django's error viewer.