Not able to find object from DB right after I created It - django

I was testing User creation by creating a TestCase, and it couldn't be found right after I created it.
I've tried to flush the cache by calling .refresh_from_db(), but it doesn't work.
Here is my TestCase:
class SuperStrangeTest(TestCase):
def test_super_strange(self):
john = User.objects.create()
john.refresh_from_db()
print('!=====START' * 10)
print(User.objects.count())
print(User.objects.all())
self.assertIsNotNone(User.objects.filter().first()) # None of assertions below would be right
self.assertIsNotNone(User.objects.filter(id=john.id).first())
self.assertTrue(User.objects.filter(id=john.id).exists())
My command to run this test is:
./manage.py test --noinput --failfast --keepdb links.tests.SuperStrangeTest.test_super_strange
The result sometimes went right, but most times it is just broken.
Using existing test database for alias 'default'...
/Users/oldcai/.virtualenvs/web/lib/python3.7/site-packages/grequests.py:21: MonkeyPatchWarning: Patching more than once will result in the union of all True parameters being patched
curious_george.patch_all(thread=False, select=False)
System check identified no issues (0 silenced).
!=====START!=====START!=====START!=====START!=====START!=====START!=====START!=====START!=====START!=====START
1
<QuerySet [<User: >]>
F
======================================================================
FAIL: test_super_strange (links.tests.SuperStrangeTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/oldcai/programs/python/webproject/zine/links/tests.py", line 41, in test_super_strange
self.assertIsNotNone(User.objects.filter().first())
AssertionError: unexpectedly None
----------------------------------------------------------------------
Ran 1 test in 0.130s
FAILED (failures=1)
Preserving test database for alias 'default'...
Errors of other lines:
======================================================================
FAIL: test_super_strange (links.tests.SuperStrangeTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/oldcai/programs/python/webproject/links/tests.py", line 35, in test_super_strange
self.assertTrue(User.objects.filter(id=john.id).exists())
AssertionError: False is not true
----------------------------------------------------------------------
======================================================================
FAIL: test_super_strange (links.tests.SuperStrangeTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/oldcai/programs/python/webproject/links/tests.py", line 35, in test_super_strange
self.assertTrue(User.objects.filter(id=john.id).exists())
AssertionError: False is not true
----------------------------------------------------------------------

Try to fill your model fields. It's base Django User model - it requires username and password. Also to create django user - use create_user function, that function will hash the password for you. Try to correct you code like that:
...
john = User.objects.create_user(username='john', password='password')
...

After diagnosed deeper into this issue, it appears that this error relates to my DATABASE_ROUTERS setting.
I'm routing the reading part of operations to a random read-only slave database in production to balancing the load of reading.
In TestCase, I set the configs of the slave database just equal to the default one.
DATABASE = {
'ENGINE': 'django.db.backends.postgresql',
'ATOMIC_REQUESTS': False,
'CONN_MAX_AGE': 0,
'NAME': 'test',
'USER': 'test',
'PASSWORD': 'test',
'HOST': '',
'PORT': '',
}
DATABASES = {
'default': DATABASE,
'replica1': DATABASE,
}
But it still not able to query out the result with replica1 right after a record inserted by default database.
When the router randomly chose the default database as the one to read from, the TestCase would pass, otherwise, it would fail.

Related

Django AssertionError - 302 is not 302

I have a super simple unit test set up for an endpoint that accepts POST requests with a file, and upon successful upload redirects the user to a new page. The goal of this unit test it to ensure file uploads are working properly.
tests.py
c = Client()
with open('replays/static/test.txt', 'r', ) as f:
response = c.post(
'/upload/',
{
'summoner': 'test user',
'title': 'Testing title',
'replay': f
},
follow=False
)
print(response.status_code)
print(response.status_code == 302)
self.assertIs(response.status_code, 302)
Output
$ python manage.py test replays
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
302
True
======================================================================
FAIL: test_create_replay (replays.tests.ReplayCreationTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/project/tests.py", line 52, in test_create_replay
self.assertIs(response.status_code, 302)
AssertionError: 302 is not 302
----------------------------------------------------------------------
Ran 1 test in 0.173s
FAILED (failures=1)
Destroying test database for alias 'default'...
If I change the parameter for following redirects when calling the test client's post method, everything works as expected with a response_status of 200
tests.py - follow redirect
c = Client()
with open('replays/static/test.txt', 'r', ) as f:
response = c.post(
'/upload/',
{
'summoner': 'test user',
'title': 'Testing title',
'replay': f
},
follow=True
)
print(response.status_code)
print(response.status_code == 200)
self.assertIs(response.status_code, 200)
Output
$ python manage.py test replays
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
200
True
.
----------------------------------------------------------------------
Ran 1 test in 0.196s
OK
Destroying test database for alias 'default'...
What am I missing? It doesn't seem like this should be the expected behavior of the assertion statement. I am using Django 3.1.
AssertIs checks if x is y, in other words, that x and y refer to the same object. But you can have two int objects that are both 302, but not the same object.
You should use .AssertEqual(…) [Python-doc]:
self.assertEqual(302, response.status_code)
For small integers, the CPython interpreter will construct int objects for -5 to 256, and thus work with a flyweight pattern:
The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object.
This means that for int between -5 and 256, it will refer to the same object, for values outside that range, it often constructs a new object.

Python: Problem with logging.error(traceback.format_exception)

I have following code:
def tearDown(self):
e_type, e_value, tb = sys.exc_info()
if e_type is not None:
logging.error((traceback.format_exception(e_type, e_value, tb)))
when I used Python 2.7 everything works fine, but after upgrade to version 3.6 it doesn't work anymore:
For example I have created some example for testing and I expect error.
def test_create_new_user_without_all_fields1(self):
self.assertEqual('USER_1', 'USER_2')
logging.info('test_create_new_user_without_all_fields1: Passed')
Result in console:
======================================================================
FAIL: test_create_new_user_without_all_fields1 (test_testExample.BaseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Dev\git\CST\tests\test_testExample.py", line 16, in test_create_new_user_without_all_fields1
self.assertEqual('USER_1', 'USER_2')
AssertionError: 'USER_1' != 'USER_2'
- USER_1
+ USER_2
? +
lets add small print to tearDown:
print (sys.exc_info())
Result:
(None, None, None)
As can we see there is no exceptions anymore, but should be. How to fix this problem ?
e_type, e_value, tb = self._outcome.errors[1][1]
logging.error(''.join(traceback.format_exception(e_type, e_value, tb)))

Testing Django Rest Framework POST returns 500 despite call working

Update
This issue was caused by me not including a token in the APIClient's header. This is resolved.
I have a standard ModelViewSet at /test-endpoint. I am trying to use APIClient to test the endpoint.
from rest_framework.test import APIClient
... # During this process, a file is uploaded to S3. Could this cause the issue? Again, no errors are thrown. I just get a 500.
self.client = APIClient()
...
sample_call = {
"name": "test_document",
"description": "test_document_description"
}
response = self.client.post('/test-endpoint', sample_call, format='json')
self.assertEqual(response.status_code, 201)
This call works with the parameters I set in sample_call. It returns a 201. When I run the test, however, I get a 500. How can I modify this to get the 201 passed?
I run the tests with python src/manage.py test modulename
To rule out the obvious, I copy-pasted the sample call into Postman and run it without issue. I believe the 500 status code is coming from the fact that I'm testing the call and not using it in a live environment.
No error messages are being thrown beyond the AssertionError:
AssertionError: 500 != 201
Full Output of testing
/home/bryant/.virtualenvs/REDACTED/lib/python3.4/site- packages/django_boto/s3/shortcuts.py:28: RemovedInDjango110Warning: Backwards compatibility for storage backends without support for the `max_length` argument in Storage.get_available_name() will be removed in Django 1.10.
s3.save(full_path, fl)
F
======================================================================
FAIL: test_create (sample.tests.SampleTestCase)
Test CREATE Document
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/bryant/api/redacted/src/sample/tests.py", line 31, in test_create
self.assertEqual(response.status_code, 201)
AssertionError: 500 != 201
----------------------------------------------------------------------
Ran 1 test in 2.673s
FAILED (failures=1)
Destroying test database for alias 'default'...
The S3 warning is expected. Otherwise, all appears normal.
To debug a failing test case in Django/DRF:
Put import pdb; pdb.set_trace() just before the assertion and see the request.content as suggested by #Igonato, or you can just add a print(request.content), there is no shame for it.
Increase verbosity of your tests by adding -v 3
Use dot notation to investigate the specific test case: python src/manage.py test modulename.tests.<TestCase>.<function>
I hope these are useful to keep in mind.

2 arguments missing but method works

Could you help me understand what is going on here. The question is about the error in the traceback. The failure is just as the illustration. And what I would like to illustrate that the function works.
Well, I was told that 2 positional arguments: 'view_instance' and 'address' are missing.
But the method really has taken those 2 positional arguments and worked happily till its logical end. In the interactive playing I show that I can catch the arguments transmitted.
Why does error appear? Thank you in advance for your help.
ADDED LATER:
Well, this seems to be because of the 'test_' beginning of the function.
Without "test" it works (def anonymous_user_redirected_to_login_page(self, view_instance, address):).
/photoarchive/general/tests.py
class GeneralTest(TestCase):
def test_anonymous_user_redirected_to_login_page(self, view_instance, address):
pdb.set_trace()
request = RequestFactory().get(address)
request.user = AnonymousUser()
response = view_instance(request)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['location'], '/accounts/login/')
def test_anonymous_user_from_home_page_redirected_to_login_page(self):
view_instance = HomePageView.as_view()
address = '/'
self.test_anonymous_user_redirected_to_login_page(view_instance, address)
Traceback
(photoarchive) michael#michael:~/workspace/photoarchive/photoarchive$ python manage.py test general
Creating test database for alias 'default'...
FE
======================================================================
ERROR: test_anonymous_user_redirected_to_login_page (general.tests.GeneralTest)
----------------------------------------------------------------------
TypeError: test_anonymous_user_redirected_to_login_page() missing 2 required positional arguments: 'view_instance' and 'address'
======================================================================
FAIL: test_anonymous_user_from_home_page_redirected_to_login_page (general.tests.GeneralTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/michael/workspace/photoarchive/photoarchive/general/tests.py", line 29, in test_anonymous_user_from_home_page_redirected_to_login_page
self.test_anonymous_user_redirected_to_login_page(view_instance, address)
File "/home/michael/workspace/photoarchive/photoarchive/general/tests.py", line 23, in test_anonymous_user_redirected_to_login_page
self.assertEqual(response.status_code, 302)
AssertionError: 200 != 302
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (failures=1, errors=1)
Destroying test database for alias 'default'...
Interactive playing:
(photoarchive) michael#michael:~/workspace/photoarchive/photoarchive$ python manage.py test general
Creating test database for alias 'default'...
> /home/michael/workspace/photoarchive/photoarchive/general/tests.py(20)test_anonymous_user_redirected_to_login_page()
-> request = RequestFactory().get(address)
(Pdb) view_instance
<function HomePageView at 0x7faa0f76fea0>
(Pdb) address
'/'
(Pdb)
test_anonymous_user_redirected_to_login_page() method is treated by unittest framework as a test method, because its name starts with test. The framework tries to execute it, but is not passing any arguments to it (test methods don't normally take any arguments). However, the method requires them, hence the error.
If this method is only a helper method to be called from the other method, name it so that it doesn't start with test, e.g. _test_anonymous_user_redirected_to_login_page().
Note that the traceback is not related to this problem. The traceback simply shows where the other test method failed at an assertion. That is, the other test method runs correctly (both in unittest run and in your interactive session).

My first unit test, what am I doing wrong?

This is my first time trying to write a test and I'm guessing I made some obvious screw up with writing the test itself.
Here is my test:
from django.test import TestCase
from accounts.forms import UserReview
class MyTests(TestCase):
def test_forms(self):
form_data = {'headline': 'test', 'body_text': 'description of item Im selling', 'author: ben'}
form = SellForm(data=form_data)
self.assertEqual(form.is_valid(), True)
I am getting the following error:
ImportError: Failed to import test module: accounts.tests
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/loader.py", line 254, in _find_tests
module = self._get_module_from_name(name)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/loader.py", line 232, in _get_module_from_name
__import__(name)
File "/Users/benjamino/Desktop/myproject/myproject/accounts/tests.py", line 8
form_data = {'headline': 'test', 'body_text': 'description of item Im selling', 'author: ben'}
^
SyntaxError: invalid syntax
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
Destroying test database for alias 'default'...
Why is accounts.tests failing to import? The code above is located in my accounts/tests.py.
The exception is clear on where the error is :
File "/Users/benjamino/Desktop/myproject/myproject/accounts/tests.py", line 8
form_data = {'headline': 'test', 'body_text': 'description of item Im selling', 'author: ben'}
^
SyntaxError: invalid syntax
Take a better look at the form_data: {'headline': 'test', 'body_text': 'description of item Im selling', 'author: ben'} (you have included a string instead of a name: value pair in your dict)
This is a simple syntax error, as the message tells you. Your quoting is wrong in the last element of your dict: 'author: ben' should be 'author': 'ben'
It's clear from the exception itself that the error is in your syntax. The form data format should be {name : value} but in your case it's {'string : value'} and if that doesn't solved your problem,maybe this could help you
Link