# -*- coding: utf-8 -*-
"""
Contains questionnaire tests. By default only tests the
wizard questionnaire processes only for one diagnose. But all other forms
are tested seperately.
:subtitle:`Class definitions:`
"""
import json
from apps.questionnaire.models import QuestionnaireRequest, get_model_class
from core.serializers import AllFieldsSerializer
from core.unittest.baseunittest import BaseUnitTest
from apps.questionnaire.forms import get_forms_for
from django.core.urlresolvers import reverse
[docs]class MockWizard:
"""
Mock Wizard object with a method for
getting the cleaned_data
"""
cleaned_data = {}
[docs]class QuestionnaireTest(BaseUnitTest):
"""
Provides tests for testing Questionnaires
"""
fixtures = ['test_data/test_users.json', ]
data = None
wizard = MockWizard()
posted_data = {}
[docs] def questionnaire_post_form(self, res, url, status_code=200,
save_and_exit=False, previous_step=False):
"""
Post a questionnaire form
Args:
- res: the response instance
- url: the url to post to
- status_code: the expected status_code (default=200)
- save_and_exit: perform a save and exit the questionnaire
- previouse_step: if True go one step back
Returns:
The response instance after posting
"""
form = res.context_data['form']
obj_deserialized = self.objects[form.Meta.model]
if obj_deserialized.object._state.adding:
obj_deserialized.save()
obj = obj_deserialized.object
form1 = form.__class__(instance=obj)
post_data = self.get_post_data(form1, form.prefix + '-')
if previous_step:
# Remove one value, so form is not valid for testing
# = saving unclean data
del post_data[post_data.keys()[0]]
current_step =\
res.context_data['wizard'][
'management_form'].initial['current_step']
post_data.update(
{res.context_data['wizard']['management_form'].prefix +
'-current_step': current_step})
if save_and_exit:
post_data.update({'save_and_exit': 'save_and_exit'})
elif previous_step:
post_data.update(
{'wizard_goto_step': res.context_data['wizard']['steps'].prev})
# save posted data
self.posted_data.update({current_step: post_data})
res = self.post(url, post_data, check_status_code=False)
if save_and_exit:
self.assertEqual(res.status_code, 302)
elif previous_step:
old_step = current_step
current_step =\
res.context_data['wizard'][
'management_form'].initial['current_step']
self.assertEqual(res.status_code, 200)
self.assertEqual(int(current_step), int(old_step) - 1)
else:
if res.status_code == 200:
current_step = res.context_data[
'wizard']['management_form'].initial['current_step']
if res.context_data['form'].errors != {}:
import ipdb
ipdb.set_trace()
self.assertEqual(res.context_data['form'].errors, {})
return res
[docs] def run_questionnaire(self, urgent=False):
"""
Runs a complete set of questionnaires for an
urgent or normal control
Args:
- urgent: run the urgent control
"""
res = self.get('/')
patient = res.context_data['patient']
session_key = self.get_session_key(patient.health_person_id)
url = '/patient/' + session_key + '/questionnaire/start_{0}/'
if urgent:
controle = 'urgent'
else:
controle = 'controle'
res = self.get(url.format(controle), 302)
url = res.url
res = self.get(url)
while not res.status_code == 302:
res = self.questionnaire_post_form(res, url)
# get finish page
res = self.get(res.url)
[docs] def get_questionnaire_fields_from_object(self, obj):
"""
Gets the questionnaire fields from a given questionnaire instance
Args:
- obj: the Questionnaire instance
Returns:
- All fields from the obj
"""
# Since Django serializer does not work with model inheritance
serializer = AllFieldsSerializer()
field_names = [x.name for x in obj._meta.get_fields()]
# Remove #####_ptr fields to super models
if obj._meta.parents != {}:
for key in obj._meta.parents:
field_names.remove(obj._meta.parents[key].name)
serializer.serialize([obj], fields=field_names)
fields = serializer.getvalue()[0]['fields']
del fields['request_step']
del fields['id']
return fields
[docs] def run_questionnaire_for_patient(self, email, urgent=False):
"""
Runs a full control for a patient
Args:
- email: the email to use for login
- urgent: if true run it for an urgent control
"""
self.login(email)
if not self.data:
self.data = self.load_data('test_data/test_data.json')
# Run through the questionnaire process
self.run_questionnaire(urgent)
# test if saved correctly in database
questionnaire_request = QuestionnaireRequest.objects.latest('pk')
for rq_step in questionnaire_request.requeststep_set.all().order_by(
'step_nr'):
saved_fields = self.get_questionnaire_fields_from_object(
rq_step.questionnaire)
obj = self.objects[rq_step.questionnaire.__class__].object
test_fields = self.get_questionnaire_fields_from_object(obj)
# Check if field is same stored as in the test dataset
self.assertEqual(test_fields, saved_fields)
[docs] def check_controle_process(self):
"""
To speed up testing only do the whole control and urgent control
for one patient. All other forms that are not hit by this test
are tested in the 'check_other_forms' function
Currently testes the following diagnoses:
colitis_ulcerosa (= same as chron), intestinal_transplantation,
rheumatoid_arthritis
"""
to_test = [
'frank@example.com', # rheumatoid_arthritis
'jeffrey@example.com', # colitis_ulcerosa
'hobart@example.com', # intestinal_transplantation
]
for email in to_test:
self.run_questionnaire_for_patient(email)
for email in to_test:
self.run_questionnaire_for_patient(email, urgent=True)
[docs] def check_controle_navigation(self, urgent):
"""
Partially fill in control and check the navigation functionality +
save partially filled in & return
"""
self.login('frank@example.com')
# Reset the posted_data store
self.posted_data = {}
if not self.data:
self.data = self.load_data('test_data/test_data.json')
res = self.get('/')
patient = res.context_data['patient']
session_key = self.get_session_key(patient.health_person_id)
start_url = '/patient/' + session_key + '/questionnaire/start_{0}/'
if urgent:
controle = 'urgent'
else:
controle = 'controle'
# create start_url
start_url = start_url.format(controle)
# Delete one via the view
questionnaire = QuestionnaireRequest.objects.first()
if questionnaire:
self.post(
reverse(
'questionnaire_request_remove',
args=[session_key, questionnaire.id]),
{},
status_code=200)
# Delete all request for this test
QuestionnaireRequest.objects.all().delete()
res = self.get(start_url, 302)
url = res.url
res = self.get(url)
# Post some forms
for i in range(1, 3):
res = self.questionnaire_post_form(res, url)
# Go back one step
res = self.questionnaire_post_form(res, url, previous_step=True)
# Save and exit
res = self.questionnaire_post_form(res, url, save_and_exit=True)
# Check saved unclean data
questionnaire = QuestionnaireRequest.objects.latest('pk')
storage = questionnaire.wizarddatabasestorage_set.all()[0]
data = json.loads(storage.data)
# Loop through saved posted_data and compare to
# stored json data (which is also posted_data)
for key in self.posted_data:
for item in self.posted_data[key]:
if data['step_data'][key]:
data_item = data['step_data'][key][item]
test_item = self.posted_data[key][item]
self.assertIn(str(test_item), data_item)
# Check unclean data is stored for step 2
for key in data['unclean_data']:
for item in data['unclean_data'][key]:
data_item = data['unclean_data'][key][item]
test_item = self.posted_data[key][item]
self.assertIn(str(test_item), data_item)
# relaunch the questionnaire
res = self.get(start_url)
self.assertEqual(res.status_code, 200)
self.assertIn('fill_in_url', res.context)
# Link into current questionnaire form
res = self.get(res.context['fill_in_url'])
current_step =\
res.context_data['wizard'][
'management_form'].initial['current_step']
# Check if we are in step 2
self.assertEqual(current_step, '2')
# Check if the initial data is set from the unclean_data
prefix = res.context['form'].prefix
for key in res.context_data['form'].initial:
test_item = res.context_data['form'].initial[key]
item = prefix + '_' + key
if item in data['unclean_data'][prefix]:
data_item = data['unclean_data'][prefix][item]
self.assertIn(str(test_item), data_item)
# delete the questionnaire
res = self.post(start_url, {})
[docs] def test_controles(self):
"""
Questionnaire tests runner
"""
self.check_controle_process()
# self.check_other_forms()
self.check_controle_navigation(urgent=False)
self.check_controle_navigation(urgent=True)