I started writing my first tests in django. I have problem with testing POST method based on model.
My project tree looks:
- db.sqlite3
- manage.py
- tree.txt
-
----api
- - admin.py
- - apps.py
- - models.py
- - serializers.py
- - urls.py
- - views.py
- - __init__.py
- -
- ----migrations
- - - 0001_initial.py
- - - __init__.py
- - -
- -
- ----tests
- - - test_models.py
- - - test_urls.py
- - - test_views.py
- - - __init__.py
- - -
- -
-
----drummingpractice
- - asgi.py
- - settings.py
- - urls.py
- - wsgi.py
- - __init__.py
- -
-
----frontend
- - admin.py
- - apps.py
- - models.py
- - urls.py
- - views.py
- - __init__.py
- -
- ----migrations
- - - __init__.py
- - -
- -
- ----templates
- - ----frontend
- - exercises_catalog.html
- - exercise_add.html
- - workouts_history.html
- - workouts_stats.html
- - workout_add.html
- -
- ----tests
- - - test_models.py
- - - test_urls.py
- - - test_views.py
- -
-
----static
I writing tests for app 'frontend'. I tried test function 'add_exercises'
frontend.views.py
def add_exercise(request):
if request.method == 'POST':
data = request.POST
how_many_img = len(request.FILES.getlist('images'))
next_exercise_id = Exercises.objects.values('exercise_id').order_by('-exercise_id')[0]['exercise_id'] + 1
# selected module
if data['module'] != 'none':
img_path = '/exercises_img/{module_id}/{exercise_id}/'.format(module_id=data['module'],
exercise_id=next_exercise_id)
module_id = data['module']
# create new module
elif data['module_new'] != '':
Modules.objects.get_or_create(module_name=data['module_new']) # insert modules...
new_module_id = Modules.objects.values('module_id').get(module_name=data['module_new'])['module_id'] # get newest module_id
img_path = '/exercises_img/{module_id}/{exercise_id}/'.format(module_id=new_module_id,
exercise_id=next_exercise_id)
module_id = new_module_id
else:
return HttpResponse('Select existing module or create new')
result = upload_file(request=request, module_id=module_id, exercise_id=next_exercise_id)
if result:
# change format dd/mm/YYYY HH:SS -> dd-mm-YYYY HH:SS
lesson_datetime_normalized = data['lesson_datetime'].replace('/', '-')
exercise = Exercises.objects.create(
exercise_name=data['exercise_name'],
module=Modules.objects.get(module_id=module_id),
lesson_datetime=lesson_datetime_normalized,
lesson_tempo=data['lesson_tempo'],
img_path=img_path,
note=data['note'],
how_many_img=how_many_img
)
return redirect('catalog')
else:
return HttpResponse('Something wrong with upload image')
elif request.method == 'GET':
print('jestem w get')
#modules = Modules.objects.all().order_by('module_id')
modules = Modules.objects.raw(
'select * from modules order by module_id asc;')
context = {'modules': modules}
return render(request, 'frontend/exercise_add.html', context)
My 'test_views.py' file in frontend app looks like:
frontend.tests.test_views.py
from django.test import TestCase, Client
from django.urls import reverse
from django.apps import apps
Modules = apps.get_model('api', 'Modules')
Exercises = apps.get_model('api', 'Exercises')
Workouts = apps.get_model('api', 'Workouts')
class TestViews(TestCase):
def setUp(self):
self.client = Client()
self.catalog_url = reverse('catalog')
self.workouts_url = reverse('workouts')
self.stats_url = reverse('stats')
self.add_exercise_url = reverse('exercise-add')
def test_catalog_GET(self):
response = self.client.get(self.catalog_url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'frontend/exercises_catalog.html')
def test_workouts_GET(self):
response = self.client.get(self.workouts_url)
self.assertIsNotNone(response.context['workouts']) # verify if context is not None
self.assertEqual(response.status_code, 200) # verify status_code
self.assertTemplateUsed(response, 'frontend/workouts_history.html')
def test_stats_GET(self):
response = self.client.get(self.stats_url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'frontend/workouts_stats.html')
def test_add_exercise_GET(self):
response = self.client.get(self.add_exercise_url)
self.assertEqual(response.status_code, 200) # undefinedTable 'modules' not exist
self.assertTemplateUsed(response, 'frontend/exercise_add.html')
def test_add_exercise_POST(self):
response = self.client.post(self.add_exercise_url, {
'exercise_name': 'exercise test 1',
'module': 1,
'lesson_datetime': '01-01-2021 10:00',
'lesson_tempo': 70,
'img_path': '/exercises_img/test/100/',
'note': 'notatka testowa',
'how_many_img': 1
})
self.assertEquals(response.status_code, 302) # undefinedTable 'exercises' not exist
First 3 tests run ok, but 'test_add_exercise_GET' and 'test_add_exercise_POST' throws errors.
Traceback (most recent call last):
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\drummingpractice\frontend\tests\test_views.py", line 69, in test_add_exercise_POST
'how_many_img': 1
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\test\client.py", line 751, in post
response = super().post(path, data=data, content_type=content_type, secure=secure, **extra)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\test\client.py", line 408, in post
secure=secure, **extra)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\test\client.py", line 473, in generic
return self.request(**r)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\test\client.py", line 719, in request
self.check_exception(response)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\test\client.py", line 580, in check_exception
raise exc_value
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\drummingpractice\frontend\views.py", line 32, in add_exercise
next_exercise_id = Exercises.objects.values('exercise_id').order_by('-exercise_id')[0]['exercise_id'] + 1
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\models\query.py", line 317, in __getitem__
qs._fetch_all()
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\models\query.py", line 1324, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\models\query.py", line 109, in __iter__
for row in compiler.results_iter(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size):
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\models\sql\compiler.py", line 1124, in results_iter
results = self.execute_sql(MULTI, chunked_fetch=chunked_fetch, chunk_size=chunk_size)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\models\sql\compiler.py", line 1169, in execute_sql
cursor.execute(sql, params)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\backends\utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\backends\utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "C:\Users\Andrzej\PycharmProjects\DrummingPractice\venv\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: BŁĄD: relation "exercises" does not exist
LINE 1: SELECT "exercises"."exercise_id" FROM "exercises" ORDER BY "...
^
I think the problem is with my models, because I using models from 'api' in 'frontend' app. I tried solutions from SO with 'makemigrations' and 'migrate', but I get 'no changes detected'. I tried also reset migrations from api and generate from 0, but still the same.
Anybody have idea what's going wrong? If architecture with models from different app is okay?
models.py (api app)
from django.db import models
class Exercises(models.Model):
exercise_id = models.AutoField(primary_key=True)
exercise_name = models.CharField(max_length=500, blank=True, null=True)
module = models.ForeignKey('Modules', models.DO_NOTHING, blank=True, null=True)
lesson_datetime = models.DateTimeField(blank=True, null=True)
lesson_tempo = models.IntegerField(blank=True, null=True)
img_path = models.CharField(max_length=500, blank=True, null=True)
note = models.CharField(max_length=500, blank=True, null=True)
how_many_img = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'exercises'
class Modules(models.Model):
module_id = models.AutoField(primary_key=True)
module_name = models.CharField(max_length=500, blank=True, null=True)
note = models.CharField(max_length=500, blank=True, null=True)
class Meta:
managed = False
db_table = 'modules'
class Workouts(models.Model):
workout_id = models.AutoField(primary_key=True)
exercise = models.ForeignKey(Exercises, models.DO_NOTHING, blank=True, null=True)
workout_datetime_start = models.DateTimeField(blank=True, null=True)
workout_datetime_end = models.DateTimeField(blank=True, null=True)
workout_tempo = models.IntegerField(blank=True, null=True)
video_path = models.CharField(max_length=500, blank=True, null=True)
note = models.CharField(max_length=500, blank=True, null=True)
class Meta:
managed = False
db_table = 'workouts'
models.py (frontend app) is empty
My tables in postgresql are (skipping django tables):
Names are correctly, lower case.
As I could see, the test with error is test_add_exercise_POST
, and it's because you start with an empty database in test enviroment, you can't do Exercises.objects.values('exercise_id').order_by('-exercise_id')[0]['exercise_id'] + 1
inside add_exercise
function, before creating test exercises objects and saving on test database.