Django Unit tests can't ovveride variable from tessting when post
I need a test for update view.
My update view creates folders. For tests I want to change path of the folders. I tried to change settings with override_settings
decorator and with with self.settings():
statment from https://docs.djangoproject.com/en/2.2/topics/testing/tools/#django.test.modify_settings
But when I run post in my test the folders are created according to settings of my project not test settings.
The path for creating the folders in my settings is saving in variable CERTIFICATION_WORKS_ROOT
.
In my view I import it as from django.conf import settings
and then output_path = settings.CERTIFICATION_WORKS_ROOT
. For debugging I added in view print(f'output_path in view - {output_path}')
, and in my test print(f'test settings - {settings.CERTIFICATION_WORKS_ROOT}')
.
In my settings the variable is defined as:
CERTIFICATION_WORKS_ROOT = os.path.join('/home/oleh/Documents/certDB_output/')
Here is my update view class:
...
from django.conf import settings
output_path = settings.CERTIFICATION_WORKS_ROOT
print(f'output_path in view - {output_path}')
...
class UpdateCase(LoginRequiredMixin, PassRequestToFormViewMixin, UpdateView):
model = Case
login_url = reverse_lazy('login')
template_name = 'case/update_case.html'
form_class = CaseForm
def summary_list(self):
work_list = CertificationByDocumentAnalysis.\
objects.filter(case=self.object).values(
'id',
'work_number',
'startdate',
'work_type',
'producer__name',
'producer__address',
'producer__code',
'case__id',
'case__agreement'
)
conformity_assessment_list = ConformityAssessment.\
objects.filter(case=self.object).values(
'id',
'work_number',
'startdate',
'work_type',
'producer__name',
'producer__address',
'producer__code',
'case__id',
'case__agreement'
)
declaration_of_conformity_list = DeclarationOfConformity.\
objects.filter(case=self.object).values(
'id',
'work_number',
'startdate',
'work_type',
'producer__name',
'producer__address',
'producer__code',
'case__id',
'case__agreement'
)
hygienic_examination_list = HygienicExamination.\
objects.filter(case=self.object).values(
'id',
'work_number',
'startdate',
'work_type',
'producer__name',
'producer__address',
'producer__code',
'case__id',
'case__agreement'
)
summary_list = conformity_assessment_list.union(work_list)
summary_list = hygienic_examination_list.union(summary_list)
summary_list = declaration_of_conformity_list.union(summary_list)
summary_list = summary_list.order_by('work_number')
return summary_list
def get_context_data(self, *args, **kwargs):
context = super(UpdateCase, self).get_context_data(*args, **kwargs)
try:
calculation = Calculation.objects.\
get(case__id=self.object.id)
except Calculation.DoesNotExist:
calculation = None
case = self.object
context['path'] = get_path(case)
context['calculation'] = calculation
context['case_id'] = case.id
context['case_type'] = case.get_case_type_display
context['next'] = 'update_case'
context['summary_list'] = self.summary_list()
if calculation != None:
calculation_dailies = CalculationDaily.objects.filter(
calculation=calculation)
calculation_cars = CalculationCar.objects.filter(
calculation=calculation)
calculation_transits = CalculationExpense.objects.filter(
calculation=calculation, expenses_type='transit')
calculation_accommodations = CalculationExpense.objects.filter(
calculation=calculation, expenses_type='accommodation')
calculation_others = CalculationExpense.objects.filter(
calculation=calculation, expenses_type='other')
context['calculation_dailies'] = calculation_dailies
context['calculation_cars'] = calculation_cars
context['calculation_transits'] = calculation_transits
context['calculation_accommodations'] = calculation_accommodations
context['calculation_others'] = calculation_others
try:
business_trip = BusinessTrip.objects.get(case=case)
except BusinessTrip.DoesNotExist:
business_trip = None
context['business_trip'] = business_trip
if business_trip != None:
business_trip_cars = BusinessTripCar.objects.filter(
business_trip_employee__business_trip__id=business_trip.id)
context['business_trip_cars'] = business_trip_cars
business_trip_employees = BusinessTripEmployee.objects.filter(
business_trip__id=business_trip.id)
context['business_trip_employees'] = business_trip_employees
business_trip_expenses = BusinessTripExpense.objects.filter(
business_trip_employee__business_trip__id=business_trip.id)
context['business_trip_expenses'] = business_trip_expenses
business_trip_dailies = BusinessTripDaily.objects.filter(
business_trip_employee__business_trip__id=business_trip.id)
context['business_trip_dailies'] = business_trip_dailies
return context
def form_valid(self, form):
if self.request.user != Case.objects.get(id=self.object.id).author and self.request.user.id != 1:
return self.handle_no_permission()
new_case = self.object
old_case = Case.objects.get(id=self.object.id)
rename_case_folder(new_case, old_case)
self.object.author = Case.objects.get(id=self.object.id).author
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
'''payments = Payment.objects\
.filter(case__id=self.object.id)'''
messages.success(self.request, 'Справу успішно збережено!')
return reverse('update_case', kwargs={'pk': self.kwargs.get('pk')})
def post(self, request, *args, **kwargs):
if request.POST.get('cancel_button'):
messages.info(request, 'Редагування справи відмінено!')
return HttpResponseRedirect(reverse('cases'))
else:
return super(UpdateCase, self).post(request, *args, **kwargs)
...
def rename_case_folder(new_case, old_case, *args, **kwargs):
new_producer = kwargs.pop('new_producer', None)
new_path = get_path(new_case)
old_path = get_path(old_case)
if new_producer is not None and new_producer not in old_path:
old_path = old_path[:-(len(new_producer) + 2)]
if not os.path.exists(old_path):
os.makedirs(old_path)
if old_path != new_path:
shutil.move(old_path, new_path)
if new_case.customer != old_case.customer:
message = f"'{old_path}' moved to '{new_path}' successfully."
logger = logging.getLogger(__name__)
logger.info(message)
else:
message = f"'{old_path}' renamed to '{new_path}' successfully."
logger = logging.getLogger(__name__)
logger.info(message)
return None
...
def get_path(case):
if case.producers:
producers = ' ' + case.producers
else:
producers = ''
path = os.path.join(output_path,
get_clean_parametr(case.body.simple_name),
get_clean_parametr(case.customer.simple_name),
str(case.startdate.year),
(case.agreement.replace('/', '_')
+ ' від '
+ case.startdate.strftime('%d-%m-%Y')
+ producers
))
return path
Here is my test module:
from datetime import date
import os
from django.test import TestCase, Client, override_settings
from django.urls import reverse
from django.contrib.auth.models import User
from django.core.files.images import ImageFile
from case.models import *
TEST_WORKS_ROOT = os.path.join('/home/oleh/Documents/test_output/')
@override_settings(CERTIFICATION_WORKS_ROOT=TEST_WORKS_ROOT)
class TestCases(TestCase):
fixtures = ['cases_test_data.json']
def setUp(self):
body1 = Body.objects.get(name='body_one')
body1.logo.save('uploads/logo-UC.svg',
ImageFile(open('/home/oleh/Downloads/logo-UC.svg', 'rb'), 'logo-UC'))
self.client = Client()
# remember url to case list page
self.url = reverse('update_case', kwargs={'pk': 1})
#self.url = reverse('cases')
def test_form(self):
user = User.objects.get(id=1)
self.client.force_login(user)
response = self.client.get(self.url)
#print(response.url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'ЗМІНИТИ СПРАВУ')
self.assertContains(response, 'Додати роботу')
self.assertContains(response, 'Друк')
self.assertContains(response, 'Тип договору')
self.assertContains(response, 'Замовник')
self.assertContains(response, 'name="save_button"')
self.assertContains(response, 'name="cancel_button"')
self.assertContains(response, f'action="{self.url}"')
def test_success_update(self):
from django.conf import settings
print(f'test settings - {settings.CERTIFICATION_WORKS_ROOT}')
user = User.objects.get(id=1)
body = Body.objects.get(id=1)
customer2 = Enterprise.objects.get(id=2)
self.client.force_login(user)
with self.settings(CERTIFICATION_WORKS_ROOT=TEST_WORKS_ROOT):
from django.conf import settings
print(f'test settings - {settings.CERTIFICATION_WORKS_ROOT}')
response = self.client.post(
self.url,
{
"body": body.id,
"author": user.id,
"agreement": "7/21/1",
"agreement_number": 1,
"case_type": "СО",
"currency": "USD",
"startdate": "2022-1-2",
"enddate": "2022-1-7",
"price": 150.00,
"customer": customer2.id
},
follow=True
)
self.assertEqual(response.status_code, 200)
case = Case.objects.get(id=1)
self.assertEqual(case.body.id, 1)
self.assertEqual(case.author.id, 1)
self.assertEqual(case.agreement, "7/21/1")
self.assertEqual(case.agreement_number, 1)
self.assertEqual(case.case_type, 'СО')
self.assertEqual(case.currency, 'USD')
self.assertEqual(case.startdate, date(2022, 1, 2))
self.assertEqual(case.enddate, date(2022, 1, 7))
self.assertEqual(case.price, 150.00)
self.assertEqual(case.customer.id, 2)
self.assertContains(response, 'Справу успішно збережено!')
self.assertEqual(response.redirect_chain[0][0],
f'/update-case/{case.id}/')
from django.conf import settings
print(f'test settings - {settings.CERTIFICATION_WORKS_ROOT}')
And here is terminal output:
...
...
INFO 2022-01-23 09:45:20,665 signals: user None added Migration 0001_initial for sessions
output_path in view - /home/oleh/Documents/certDB_output/
System check identified no issues (0 silenced).
INFO 2022-01-23 09:45:22,858 signals: user None added body1
INFO 2022-01-23 09:45:22,869 signals: user None added user1
INFO 2022-01-23 09:45:22,877 signals: user None added enterprise_one, , код ЄДРПОУ:
INFO 2022-01-23 09:45:22,882 signals: user None added enterprise_two, , код ЄДРПОУ:
INFO 2022-01-23 09:45:22,913 signals: user None added body1 Договір №:7/21/1, від: 2022-01-01, Заявник: enterprise1, вартість: 100
INFO 2022-01-23 09:45:22,932 signals: user None added Справа №: 7/21/1; Сума оплати: 100; Дата оплати: 2022-01-04; Замовник: enterprise1
INFO 2022-01-23 09:45:22,961 signals: user None updated body1
INFO 2022-01-23 09:45:23,069 signals: user None added malcwkkfqvgmbwd768v4gn8f63f49tb6
INFO 2022-01-23 09:45:23,083 signals: user None added 86y7qzb4058ed9wajuqbz5t756sz1dmk
INFO 2022-01-23 09:45:23,092 signals: user None deleted malcwkkfqvgmbwd768v4gn8f63f49tb6
INFO 2022-01-23 09:45:23,103 signals: user None updated user1
INFO 2022-01-23 09:45:23,108 signals: user None updated 86y7qzb4058ed9wajuqbz5t756sz1dmk
.INFO 2022-01-23 09:45:23,381 signals: user None updated body1
test settings - /home/oleh/Documents/test_output/
INFO 2022-01-23 09:45:23,396 signals: user None added wucx5j3gd0esfm10twhf1vrtgxy8gjl7
INFO 2022-01-23 09:45:23,406 signals: user None added x0l3976s8x2hn2z8zwurilmjlzeokfk7
INFO 2022-01-23 09:45:23,412 signals: user None deleted wucx5j3gd0esfm10twhf1vrtgxy8gjl7
INFO 2022-01-23 09:45:23,417 signals: user None updated user1
INFO 2022-01-23 09:45:23,422 signals: user None updated x0l3976s8x2hn2z8zwurilmjlzeokfk7
test settings - /home/oleh/Documents/test_output/
INFO 2022-01-23 09:45:23,477 views: '/home/oleh/Documents/certDB_output/body1/enterprise1/2022/7_21_1 від 01-01-2022' moved to '/home/oleh/Documents/certDB_output/body1/enterprise2/2022/7_21_1 від 02-01-2022' successfully.
INFO 2022-01-23 09:45:23,499 signals: user None updated body1 Договір №:7/21/1, від: 2022-01-02, Заявник: enterprise2, вартість: 150.0
test settings - /home/oleh/Documents/test_output/
.
----------------------------------------------------------------------
Ran 2 tests in 0.910s
OK
Destroying test database for alias 'default'...
The folders were created in certDB_output
not in test_output
folder
As your code is currently written, settings are read only once at import time.
Remove the output_path = settings.CERTIFICATION_WORKS_ROOT
and use settings.CERTIFICATION_WORKS_ROOT
in your get_path
method.
Or, patch case.views.output_path
in your test.
Django advices against setting an alias of your settings, but thats what you did. See docs
Finally, avoid aliasing your settings as module-level constants as override_settings() won’t work on such values since they are only evaluated the first time the module is imported.
So inside get_path you should replace outout_path
with settings.CERTIFICATION_WORKS_ROOT
and it will work