【发布时间】:2023-03-16 07:04:01
【问题描述】:
我需要测试更新视图。
我的更新视图创建文件夹。对于测试,我想更改文件夹的路径。我尝试使用 override_settings 装饰器和来自 https://docs.djangoproject.com/en/2.2/topics/testing/tools/#django.test.modify_settings 的 with self.settings(): statment 更改设置
但是当我在测试中运行 post 时,文件夹是根据我的项目设置而不是测试设置创建的。
在我的设置中创建文件夹的路径保存在变量CERTIFICATION_WORKS_ROOT 中。
在我看来,我将其导入为from django.conf import settings,然后是output_path = settings.CERTIFICATION_WORKS_ROOT。为了调试,我在视图print(f'output_path in view - {output_path}') 和我的测试print(f'test settings - {settings.CERTIFICATION_WORKS_ROOT}') 中添加了。
在我的设置中,变量定义为:
CERTIFICATION_WORKS_ROOT = os.path.join('/home/oleh/Documents/certDB_output/')
这是我的更新视图类:
...
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
这是我的测试模块:
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}')
这是终端输出:
...
...
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'...
文件夹是在certDB_output 而非test_output 文件夹中创建的
【问题讨论】:
-
你应该从你的视图函数中发布代码,因为这就是意外行为所在。
-
我已经发布了我的视图函数
-
您的视图函数中没有
print(f'output_path in view - {output_path}')。代码的重要部分是,您可以在其中导入from django.conf import settings,然后访问您的变量。但是在您发布的视图中,您无法访问您的设置... -
我的视图非常大(我想在将来将其重构为部分),所以我用部分更新了我的帖子,其中显示了从设置导入变量、updatecase 视图类、创建文件夹的函数
rename_case_folder和为前一个函数get_path准备路径的函数
标签: django unit-testing