def setUp(self): super(MultipleChoiceTagTests, self).setUp() self.base = '/' + COURSE_NAME self.app_context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, 'Assessment Tags') self.namespace = 'ns_%s' % COURSE_NAME with utils.Namespace(self.namespace): dto = models.QuestionDTO(None, transforms.loads(self.MC_1_JSON)) self.mc_1_id = models.QuestionDAO.save(dto) dto = models.QuestionDTO(None, transforms.loads(self.MC_2_JSON)) self.mc_2_id = models.QuestionDAO.save(dto) dto = models.QuestionGroupDTO( None, transforms.loads(self.QG_1_JSON_TEMPLATE % (self.mc_1_id, self.mc_2_id))) self.qg_1_id = models.QuestionGroupDAO.save(dto) self.course = courses.Course(None, self.app_context) self.assessment = self.course.add_assessment() self.assessment.availability = courses.AVAILABILITY_AVAILABLE self.assessment.html_content = ( '<question quid="%s" weight="1" instanceid="q1"></question>' '<question-group qgid="%s" instanceid="qg1"></question-group' % (self.mc_1_id, self.qg_1_id)) self.course.save()
def setUp(self): """Sets up datastore contents.""" super(QuestionDAOTestCase, self).setUp() self.used_twice_question_id = 1 self.used_twice_question_dto = models.QuestionDTO( self.used_twice_question_id, {}) self.used_once_question_id = 2 self.used_once_question_dto = models.QuestionDTO( self.used_once_question_id, {}) self.unused_question_id = 3 self.unused_question_dto = models.QuestionDTO(self.unused_question_id, {}) models.QuestionDAO.save_all([ self.used_twice_question_dto, self.used_once_question_dto, self.unused_question_dto ]) # Handcoding the dicts. This is dangerous because they're handcoded # elsewhere, the implementations could fall out of sync, and these tests # may then pass erroneously. self.first_question_group_description = 'first_question_group' self.first_question_group_id = 4 self.first_question_group_dto = models.QuestionGroupDTO( self.first_question_group_id, { 'description': self.first_question_group_description, 'items': [{ 'question': str(self.used_once_question_id) }] }) self.second_question_group_description = 'second_question_group' self.second_question_group_id = 5 self.second_question_group_dto = models.QuestionGroupDTO( self.second_question_group_id, { 'description': self.second_question_group_description, 'items': [{ 'question': str(self.used_twice_question_id) }] }) self.third_question_group_description = 'third_question_group' self.third_question_group_id = 6 self.third_question_group_dto = models.QuestionGroupDTO( self.third_question_group_id, { 'description': self.third_question_group_description, 'items': [{ 'question': str(self.used_twice_question_id) }] }) models.QuestionGroupDAO.save_all([ self.first_question_group_dto, self.second_question_group_dto, self.third_question_group_dto ])
def test_add_to_question_group(self): # Create a question question_description = 'Question' question_dto = models.QuestionDTO(None, { 'description': question_description, 'type': 0 # MC }) question_id = models.QuestionDAO.save(question_dto) add_to_group_selector = '.add-question-to-group' # No groups are present so no add_to_group icon should be present self.assertEqual([], self._soup_table().select(add_to_group_selector)) # Create a group qg_description = 'Question Group' qg_dto = models.QuestionGroupDTO(None, { 'description': qg_description, 'items': [] }) qg_id = models.QuestionGroupDAO.save(qg_dto) # Since we now have a group, the add_to_group icon should be visible self.assertIsNotNone( self._soup_table().select(add_to_group_selector)) # Add Question to Question Group via post_add_to_question_group questions_table = self._soup_table() xsrf_token = questions_table.get('data-qg-xsrf-token', '') response = self._call_add_to_question_group( question_id, qg_id, 1, xsrf_token) # Check if operation was successful self.assertEquals(response.status_int, 200) questions_table = self._soup_table() self.assertEquals( questions_table.select('.groups-cell li')[0].text.strip(), qg_description ) # Check a bunch of calls that should fail response = self._call_add_to_question_group(question_id, qg_id, 1, 'a') self.assertEquals(response.status_int, 403) response = transforms.loads(self._call_add_to_question_group( -1, qg_id, 1, xsrf_token).body) self.assertEquals(response['status'], 500) response = transforms.loads(self._call_add_to_question_group( question_id, -1, 1, xsrf_token).body) self.assertEquals(response['status'], 500) response = transforms.loads(self._call_add_to_question_group( 'a', qg_id, 1, xsrf_token).body) self.assertEquals(response['status'], 500) response = transforms.loads(self._call_add_to_question_group( question_id, qg_id, 'a', xsrf_token).body) self.assertEquals(response['status'], 500)
def test_no_question_groups(self): description = 'Question description' models.QuestionDAO.save( models.QuestionDTO(None, {'description': description})) table = self._soup_table() self.assertEquals(description, table.select('.description-cell a')[0].text.strip())
def test_no_question_groups(self): description = 'Question description' models.QuestionDAO.save( models.QuestionDTO(None, {'description': description})) asset_tables = self._load_tables() self.assertEquals(asset_tables[0].findall('./tbody/tr/td/a')[1].tail, description) self.assertEquals(asset_tables[1].find('./tfoot/tr/td').text, 'No question groups available')
def test_last_modified_timestamp(self): begin_time = time.time() question_dto = models.QuestionDTO(None, {}) models.QuestionDAO.save(question_dto) self.assertTrue((begin_time <= question_dto.last_modified) and (question_dto.last_modified <= time.time())) questions_table = self._soup_table() self.assertEquals( questions_table.select('[data-timestamp]')[0].get( 'data-timestamp', ''), str(question_dto.last_modified))
def convert_to_dtos(self, questions): dtos = [] for question in questions: question['version'] = models.QuestionDAO.VERSION dto = models.QuestionDTO(None, question) if dto.type == 'multi_choice': dto.type = models.QuestionDTO.MULTIPLE_CHOICE else: dto.type = models.QuestionDTO.SHORT_ANSWER dtos.append(dto) return dtos
def test_table_entries(self): # Create a question mc_question_description = 'Test MC Question' mc_question_dto = models.QuestionDTO( None, { 'description': mc_question_description, 'type': 0 # MC }) mc_question_id = models.QuestionDAO.save(mc_question_dto) # Create a question group and add the question qg_description = 'Question Group' qg_dto = models.QuestionGroupDTO( None, { 'description': qg_description, 'items': [{ 'question': str(mc_question_id) }] }) qg_id = models.QuestionGroupDAO.save(qg_dto) # Create a second assessment and add the question group to the content assessment_two = self.course.add_assessment() assessment_two.title = 'Test Assessment' assessment_two.html_content = """ <question-group qgid="%s" instanceid="QG"></question-group> """ % qg_id self.course.save() # Check Question Group table question_groups_table = self._soup_table() row = question_groups_table.select('tbody tr')[0] # Check edit link and description edit_link = row.select('.description-cell a')[0] self.assertEquals(edit_link.text.strip(), qg_description) self.assertEquals( edit_link.get('href'), 'dashboard?action=edit_question_group&key={}'.format(qg_id)) # The question that is part of this group, should be listed self.assertEquals( row.select('.questions-cell li')[0].text.strip(), mc_question_description) # Assessment where this Question Group is located, should be linked location_link = row.select('.locations-cell a')[0] self.assertEquals(location_link.get('href'), 'assessment?name={}'.format(assessment_two.unit_id)) self.assertEquals(assessment_two.title, location_link.text.strip())
def test_unused_question(self): # Create an unused question unused_question_dto = models.QuestionDTO(None, { 'description': 'unused', 'type': 0 }) unused_question_id = models.QuestionDAO.save(unused_question_dto) self.course.save() dom = self.parse_html_string(self.get(self.URL).body) question_row = dom.find( './/tr[@data-quid=\'{}\']'.format(unused_question_id)) filter_data = json.loads(question_row.get('data-filter')) self.assertEqual(filter_data['unused'], 1)
def test_question_clone(self): # Add a question by just nailing it in to the datastore. mc_question_description = 'Test MC Question' mc_question_dto = models.QuestionDTO( None, { 'description': mc_question_description, 'type': 0 # MC }) models.QuestionDAO.save(mc_question_dto) # On the assets -> questions page, clone the question. response = self.get(self.URL) dom = self.parse_html_string(self.get(self.URL).body) clone_link = dom.find('.//a[@class="icon icon-clone"]') response = self.get(clone_link.get('href'), response).follow() self.assertIn(mc_question_description + ' (clone)', response.body)
def test_last_modified_timestamp(self): begin_time = time.time() question_dto = models.QuestionDTO(None, {}) models.QuestionDAO.save(question_dto) self.assertTrue((begin_time <= question_dto.last_modified) and (question_dto.last_modified <= time.time())) qg_dto = models.QuestionGroupDTO(None, {}) models.QuestionGroupDAO.save(qg_dto) self.assertTrue((begin_time <= qg_dto.last_modified) and (question_dto.last_modified <= time.time())) asset_tables = self._load_tables() self.assertEquals( asset_tables[0].find('./tbody/tr/td[@data-timestamp]').get( 'data-timestamp', ''), str(question_dto.last_modified)) self.assertEquals( asset_tables[1].find('./tbody/tr/td[@data-timestamp]').get( 'data-timestamp', ''), str(qg_dto.last_modified))
def test_question_clone(self): # Add a question by just nailing it in to the datastore. mc_question_description = 'Test MC Question' mc_question_dto = models.QuestionDTO( None, { 'description': mc_question_description, 'type': 0 # MC }) models.QuestionDAO.save(mc_question_dto) # On the assets -> questions page, clone the question. response = self.get(self.URL) soup = self.parse_html_string_to_soup(self.get(self.URL).body) clone_link = soup.select('.clone-question')[0] question_key = clone_link.get('data-key') xsrf_token = soup.select('#question-table')[0].get( 'data-clone-question-token') self.post('dashboard?action=clone_question', { 'key': question_key, 'xsrf_token': xsrf_token }) response = self.get(self.URL) self.assertIn(mc_question_description + ' (clone)', response.body)
def test_question_clone(self): # Add a question by just nailing it in to the datastore. mc_question_description = 'Test MC Question' mc_question_dto = models.QuestionDTO(None, { 'description': mc_question_description, 'type': 0 # MC }) models.QuestionDAO.save(mc_question_dto) # On the assets -> questions page, clone the question. response = self.get(self.URL) dom = self.parse_html_string(self.get(self.URL).body) clone_link = dom.find('.//a[@class="icon icon-clone"]') question_key = clone_link.get('data-key') xsrf_token = dom.find('.//table[@id="question-table"]' ).get('data-clone-question-token') self.post( 'dashboard?action=clone_question', { 'key': question_key, 'xsrf_token': xsrf_token }) response = self.get(self.URL) self.assertIn(mc_question_description + ' (clone)', response.body)
def test_table_entries(self): # Create a question mc_question_description = 'Test MC Question' mc_question_dto = models.QuestionDTO(None, { 'description': mc_question_description, 'type': 0 # MC }) mc_question_id = models.QuestionDAO.save(mc_question_dto) # Create an assessment and add the question to the content assessment_one = self.course.add_assessment() assessment_one.title = 'Test Assessment One' assessment_one.html_content = """ <question quid="%s" weight="1" instanceid="1"></question> """ % mc_question_id # Create a second question sa_question_description = 'Test SA Question' sa_question_dto = models.QuestionDTO(None, { 'description': sa_question_description, 'type': 1 # SA }) sa_question_id = models.QuestionDAO.save(sa_question_dto) # Create a question group and add the second question qg_description = 'Question Group' qg_dto = models.QuestionGroupDTO(None, { 'description': qg_description, 'items': [{'question': str(sa_question_id)}] }) qg_id = models.QuestionGroupDAO.save(qg_dto) # Create a second assessment and add the question group to the content assessment_two = self.course.add_assessment() assessment_two.title = 'Test Assessment' assessment_two.html_content = """ <question-group qgid="%s" instanceid="QG"></question-group> """ % qg_id self.course.save() # Get the Assets > Question tab dom = self.parse_html_string(self.get(self.URL).body) asset_tables = dom.findall('.//table[@class="assets-table"]') self.assertEquals(len(asset_tables), 2) # First check Question Bank table questions_table = asset_tables[0] question_rows = questions_table.findall('./tbody/tr[@data-filter]') self.assertEquals(len(question_rows), 2) # Check edit link and description of the first question first_row = list(question_rows[0]) first_cell = first_row[0] self.assertEquals(first_cell.findall('a')[1].tail, mc_question_description) self.assertEquals(first_cell.find('a').get('href'), ( 'dashboard?action=edit_question&key=%s' % mc_question_id)) # Check if the assessment is listed location_link = first_row[2].find('ul/li/a') self.assertEquals(location_link.get('href'), ( 'assessment?name=%s' % assessment_one.unit_id)) self.assertEquals(location_link.text, assessment_one.title) # Check second question (=row) second_row = list(question_rows[1]) self.assertEquals( second_row[0].findall('a')[1].tail, sa_question_description) # Check whether the containing Question Group is listed self.assertEquals(second_row[1].find('ul/li').text, qg_description) # Now check Question Group table question_groups_table = asset_tables[1] row = question_groups_table.find('./tbody/tr') # Check edit link and description edit_link = row[0].find('a') self.assertEquals(edit_link.tail, qg_description) self.assertEquals(edit_link.get('href'), ( 'dashboard?action=edit_question_group&key=%s' % qg_id)) # The question that is part of this group, should be listed self.assertEquals(row[1].find('ul/li').text, sa_question_description) # Assessment where this Question Group is located, should be linked location_link = row[2].find('ul/li/a') self.assertEquals(location_link.get('href'), ( 'assessment?name=%s' % assessment_two.unit_id)) self.assertEquals(location_link.text, assessment_two.title)
def test_table_entries(self): # Create a question mc_question_description = 'Test MC Question' mc_question_dto = models.QuestionDTO( None, { 'description': mc_question_description, 'type': 0 # MC }) mc_question_id = models.QuestionDAO.save(mc_question_dto) # Create an assessment and add the question to the content. # Also include a broken question ref to the assessment (and expect this # doesn't break anything). assessment_one = self.course.add_assessment() assessment_one.title = 'Test Assessment One' assessment_one.html_content = """ <question quid="%s" weight="1" instanceid="1"></question> <question quid="broken" weight="1" instanceid="broken"></question> """ % mc_question_id # Create a second question sa_question_description = 'Test SA Question' sa_question_dto = models.QuestionDTO( None, { 'description': sa_question_description, 'type': 1 # SA }) sa_question_id = models.QuestionDAO.save(sa_question_dto) # Create a question group and add the second question qg_description = 'Question Group' qg_dto = models.QuestionGroupDTO( None, { 'description': qg_description, 'items': [{ 'question': str(sa_question_id) }] }) qg_id = models.QuestionGroupDAO.save(qg_dto) # Create a second assessment and add the question group to the content assessment_two = self.course.add_assessment() assessment_two.title = 'Test Assessment' assessment_two.html_content = """ <question-group qgid="%s" instanceid="QG"></question-group> """ % qg_id self.course.save() # First check Question Bank table questions_table = self._soup_table() question_rows = questions_table.select('tr[data-filter]') self.assertEquals(len(question_rows), 2) # Check edit link and description of the first question first_row = question_rows[0] description_link = first_row.select('.description-cell a')[0] self.assertEquals(description_link.text.strip(), mc_question_description) self.assertEquals( description_link.get('href'), ('dashboard?action=edit_question&key={}'.format(mc_question_id))) # Check if the assessment is listed location_link = first_row.select('.locations-cell a')[0] self.assertEquals(location_link.get('href'), 'assessment?name={}'.format(assessment_one.unit_id)) self.assertEquals(assessment_one.title, location_link.text.strip()) # Check second question (=row) second_row = question_rows[1] self.assertEquals( second_row.select('.description-cell a')[0].text.strip(), sa_question_description) # Check whether the containing Question Group is listed self.assertEquals( second_row.select('.groups-cell li')[0].text.strip(), qg_description)
def _get_sample_v15_course(self): """Creates a course with different types of questions and returns it.""" sites.setup_courses('course:/test::ns_test, course:/:/') course = courses.Course(None, app_context=sites.get_all_courses()[0]) unit1 = course.add_unit() lesson1 = course.add_lesson(unit1) assessment_old = course.add_assessment() assessment_old.title = 'Old assessment' assessment_new = course.add_assessment() assessment_new.title = 'New assessment' assessment_peer = course.add_assessment() assessment_peer.title = 'Peer review assessment' # Create a multiple choice question. mcq_new_id = 1 mcq_new_dict = { 'description': 'mcq_new', 'type': 0, # Multiple choice question. 'choices': [{ 'text': 'answer', 'score': 1.0 }], 'version': '1.5' } mcq_new_dto = models.QuestionDTO(mcq_new_id, mcq_new_dict) # Create a short answer question. frq_new_id = 2 frq_new_dict = { 'defaultFeedback': '', 'rows': 1, 'description': 'short answer', 'hint': '', 'graders': [{ 'matcher': 'case_insensitive', 'score': '1.0', 'response': 'hi', 'feedback': '' }], 'question': 'short answer question', 'version': '1.5', 'type': 1, # Short answer question. 'columns': 100 } frq_new_dto = models.QuestionDTO(frq_new_id, frq_new_dict) # Save these questions to datastore. models.QuestionDAO.save_all([mcq_new_dto, frq_new_dto]) # Create a question group. question_group_id = 3 question_group_dict = { 'description': 'question_group', 'items': [ {'question': str(mcq_new_id)}, {'question': str(frq_new_id)}, {'question': str(mcq_new_id)} ], 'version': '1.5', 'introduction': '' } question_group_dto = models.QuestionGroupDTO( question_group_id, question_group_dict) # Save the question group to datastore. models.QuestionGroupDAO.save_all([question_group_dto]) # Add a MC question and a question group to leesson1. lesson1.objectives = """ <question quid="1" weight="1" instanceid="QN"></question> random_text <gcb-youtube videoid="Kdg2drcUjYI" instanceid="VD"></gcb-youtube> more_random_text <question-group qgid="3" instanceid="QG"></question-group> """ # Add a MC question, a short answer question, and a question group to # new style assessment. assessment_new.html_content = """ <question quid="1" weight="1" instanceid="QN2"></question> <question quid="2" weight="1" instanceid="FRQ2"></question> random_text <gcb-youtube videoid="Kdg2drcUjYI" instanceid="VD"></gcb-youtube> more_random_text <question-group qgid="3" instanceid="QG2"></question-group> """ return course
def test_add_to_question_group(self): # Create a question question_description = 'Question' question_dto = models.QuestionDTO(None, { 'description': question_description, 'type': 0 # MC }) question_id = models.QuestionDAO.save(question_dto) # No groups are present so no add_to_group icon should be present self.assertIsNone(self._load_tables()[0].find('./tbody/tr/td[ul]div')) # Create a group qg_description = 'Question Group' qg_dto = models.QuestionGroupDTO(None, { 'description': qg_description, 'items': [] }) qg_id = models.QuestionGroupDAO.save(qg_dto) # Since we now have a group, the add_to_group icon should be visible self.assertIsNotNone( self._load_tables()[0].find('./tbody/tr/td[ul]/div')) # Add Question to Question Group via post_add_to_question_group asset_tables = self._load_tables() xsrf_token = asset_tables[0].get('data-qg-xsrf-token', '') response = self._call_add_to_question_group( question_id, qg_id, 1, xsrf_token) # Check if operation was successful self.assertEquals(response.status_int, 200) asset_tables = self._load_tables() self.assertEquals( asset_tables[0].find('./tbody/tr/td/ul/li').text, qg_description ) self.assertEquals( asset_tables[1].find('./tbody/tr/td/ul/li').text, question_description ) # Check a bunch of calls that should fail response = self._call_add_to_question_group(question_id, qg_id, 1, 'a') self.assertEquals(response.status_int, 403) response = transforms.loads(self._call_add_to_question_group( -1, qg_id, 1, xsrf_token).body) self.assertEquals(response['status'], 500) response = transforms.loads(self._call_add_to_question_group( question_id, -1, 1, xsrf_token).body) self.assertEquals(response['status'], 500) response = transforms.loads(self._call_add_to_question_group( 'a', qg_id, 1, xsrf_token).body) self.assertEquals(response['status'], 500) response = transforms.loads(self._call_add_to_question_group( question_id, qg_id, 'a', xsrf_token).body) self.assertEquals(response['status'], 500)