From 63ed08c050930fe9ab4057b142fa3d103ba2cfa9 Mon Sep 17 00:00:00 2001 From: Mathew May Date: Thu, 4 Jan 2024 13:57:02 +0800 Subject: [PATCH] MDL-79905 qtype_ordering: Improve test coverage for question ordering Part of: MDL-79863 --- question/type/ordering/question.php | 4 + .../specific_grade_detail_feedback_test.php | 90 ++++++++++++++++++- .../type/ordering/tests/question_test.php | 23 +++++ 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/question/type/ordering/question.php b/question/type/ordering/question.php index 8b8f3405440..4a362e6299e 100644 --- a/question/type/ordering/question.php +++ b/question/type/ordering/question.php @@ -789,6 +789,7 @@ class qtype_ordering_question extends question_graded_automatically { * * @param int|null $type * @return array|string array if $type is not specified and single string if $type is specified + * @codeCoverageIgnore */ public static function get_select_types(int $type = null): array|string { $plugin = 'qtype_ordering'; @@ -805,6 +806,7 @@ class qtype_ordering_question extends question_graded_automatically { * * @param int|null $type * @return array|string array if $type is not specified and single string if $type is specified + * @codeCoverageIgnore */ public static function get_layout_types(int $type = null): array|string { $plugin = 'qtype_ordering'; @@ -820,6 +822,7 @@ class qtype_ordering_question extends question_graded_automatically { * * @param int|null $type * @return array|string array if $type is not specified and single string if $type is specified + * @codeCoverageIgnore */ public static function get_grading_types(int $type = null): array|string { $plugin = 'qtype_ordering'; @@ -846,6 +849,7 @@ class qtype_ordering_question extends question_graded_automatically { * @param string|null $style The specific numbering style to retrieve. * @return array|string Numbering style(s). * The keys are style identifiers, and the values are the corresponding language strings. + * @codeCoverageIgnore */ public static function get_numbering_styles(string $style = null): array|string { $plugin = 'qtype_ordering'; diff --git a/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php b/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php index 77cb420e931..d0e9da0c4fd 100644 --- a/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php +++ b/question/type/ordering/tests/output/specific_grade_detail_feedback_test.php @@ -44,20 +44,23 @@ class specific_grade_detail_feedback_test extends advanced_testcase { * @param int $gradingtype Grading type. * @param string $layouttype The type of the layout. * @param array $expected The expected exported data. + * @param int $selecttype The type of the select. * @return void * @covers ::export_for_template */ - public function test_export_for_template(array $answeritems, int $gradingtype, string $layouttype, array $expected): void { + public function test_export_for_template(array $answeritems, int $gradingtype, string $layouttype, array $expected, int $selecttype): void { global $PAGE; - + $this->resetAfterTest(); $question = test_question_maker::make_question('ordering'); + // Options need to be set before starting the attempt otherwise they are not passed along. $question->options->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL : qtype_ordering_question::LAYOUT_VERTICAL; + $question->options->gradingtype = $gradingtype; + $question->options->selecttype = $selecttype; $qa = new \testable_question_attempt($question, 0); $step = new \question_attempt_step(); $qa->add_step($step); $question->start_attempt($step, 1); - $question->options->gradingtype = $gradingtype; $keys = implode(',', array_keys($answeritems)); $values = array_values($answeritems); @@ -71,7 +74,16 @@ class specific_grade_detail_feedback_test extends advanced_testcase { $specificgradedetailfeedback = new specific_grade_detail_feedback($qa); $actual = $specificgradedetailfeedback->export_for_template($renderer); - $this->assertEquals($expected, $actual); + if ($selecttype === qtype_ordering_question::SELECT_ALL) { + $this->assertEquals($expected, $actual); + } else { + // Since the order of the scores is random or contiguous, we need to check the score details separately. + $this->assertEquals($expected['showpartialwrong'], $actual['showpartialwrong']); + $this->assertEquals($expected['gradingtype'], $actual['gradingtype']); + $this->assertEquals($expected['orderinglayoutclass'], $actual['orderinglayoutclass']); + $this->assertEquals($expected['totalmaxscore'], $actual['totalmaxscore']); + $this->assertArrayHasKey('scoredetails', $actual); + } } /** @@ -91,6 +103,7 @@ class specific_grade_detail_feedback_test extends advanced_testcase { [ 'showpartialwrong' => false, ], + qtype_ordering_question::SELECT_ALL, ], 'Partially correct question attempt (horizontal layout). Relative to ALL the previous and next items' => [ [13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 17 => 'Learning', 16 => 'Dynamic', 18 => 'Environment'], @@ -112,6 +125,7 @@ class specific_grade_detail_feedback_test extends advanced_testcase { ['score' => 5, 'maxscore' => 5, 'percent' => 100], ], ], + qtype_ordering_question::SELECT_ALL, ], 'Incorrect question attempt (horizontal layout). Relative to ALL the previous and next items' => [ [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'], @@ -133,6 +147,7 @@ class specific_grade_detail_feedback_test extends advanced_testcase { ['score' => 2, 'maxscore' => 5, 'percent' => 40], ], ], + qtype_ordering_question::SELECT_ALL, ], 'Incorrect question attempt (vertical layout). Grading type: Relative to the next item (excluding last)' => [ [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'], @@ -154,6 +169,73 @@ class specific_grade_detail_feedback_test extends advanced_testcase { ['score' => 0, 'maxscore' => 1, 'percent' => 0.0], ], ], + qtype_ordering_question::SELECT_ALL, + ], + 'Incorrect question attempt (vertical layout). Grading type: GRADING_LONGEST_ORDERED_SUBSET' => [ + [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'], + qtype_ordering_question::GRADING_LONGEST_ORDERED_SUBSET, + 'vertical', + [ + 'showpartialwrong' => 1, + 'gradingtype' => 'Grading type: Longest ordered subset', + 'orderinglayoutclass' => 'vertical', + 'gradedetails' => 67.0, + 'totalscore' => 4, + 'totalmaxscore' => 6, + 'scoredetails' => [ + ['score' => 1, 'maxscore' => 1, 'percent' => 100.0], + ['score' => 1, 'maxscore' => 1, 'percent' => 100.0], + ['score' => 0, 'maxscore' => 1, 'percent' => 0.0], + ['score' => 1, 'maxscore' => 1, 'percent' => 100.0], + ['score' => 1, 'maxscore' => 1, 'percent' => 100.0], + ['score' => 0, 'maxscore' => 1, 'percent' => 0.0], + ], + ], + qtype_ordering_question::SELECT_ALL, + ], + 'Incorrect question attempt (SELECT_RANDOM). Grading type: GRADING_ABSOLUTE_POSITION' => [ + [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'], + qtype_ordering_question::GRADING_ABSOLUTE_POSITION, + 'vertical', + [ + 'showpartialwrong' => 1, + 'gradingtype' => 'Grading type: Absolute position', + 'orderinglayoutclass' => 'vertical', + 'gradedetails' => 0, + 'totalscore' => 0, + 'totalmaxscore' => 3, + 'scoredetails' => [ + ['score' => 0, 'maxscore' => 1, 'percent' => 0.0], + ['score' => 0, 'maxscore' => 1, 'percent' => 0.0], + ['score' => 0, 'maxscore' => 1, 'percent' => 0.0], + ['score' => 'No score', 'maxscore' => null, 'percent' => 0], + ['score' => 'No score', 'maxscore' => null, 'percent' => 0], + ['score' => 'No score', 'maxscore' => null, 'percent' => 0], + ], + ], + qtype_ordering_question::SELECT_RANDOM, + ], + 'Incorrect question attempt (SELECT_CONTIGUOUS). Grading type: GRADING_ABSOLUTE_POSITION' => [ + [14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'], + qtype_ordering_question::GRADING_ABSOLUTE_POSITION, + 'vertical', + [ + 'showpartialwrong' => 1, + 'gradingtype' => 'Grading type: Absolute position', + 'orderinglayoutclass' => 'vertical', + 'gradedetails' => 0, + 'totalscore' => 0, + 'totalmaxscore' => 3, + 'scoredetails' => [ + ['score' => 0, 'maxscore' => 1, 'percent' => 0], + ['score' => 1, 'maxscore' => 1, 'percent' => 100.0], + ['score' => 0, 'maxscore' => 1, 'percent' => 0], + ['score' => 'No score', 'maxscore' => null, 'percent' => 0], + ['score' => 'No score', 'maxscore' => null, 'percent' => 0], + ['score' => 'No score', 'maxscore' => null, 'percent' => 0], + ], + ], + qtype_ordering_question::SELECT_CONTIGUOUS, ], ]; } diff --git a/question/type/ordering/tests/question_test.php b/question/type/ordering/tests/question_test.php index 2a7f06aff9a..0e456435ce1 100644 --- a/question/type/ordering/tests/question_test.php +++ b/question/type/ordering/tests/question_test.php @@ -555,6 +555,15 @@ class question_test extends \advanced_testcase { ) ); $this->assertEquals($expected, $actual); + + // Confirm that if a passed array contains an item that does not exist in the question, it is ignored. + $actual = $question->summarise_response( + qtype_ordering_test_helper::get_response( + $question, + ['notexist'] + ) + ); + $this->assertEquals('', $actual); } public function test_initialise_question_instance(): void { @@ -575,6 +584,10 @@ class question_test extends \advanced_testcase { } else if ($question->options->layouttype === 1) { $this->assertEquals('horizontal', $question->get_ordering_layoutclass()); } + // Confirm that if an invalid layouttype is set, an empty string is returned. + $question->options->layouttype = 3; + $error = $question->get_ordering_layoutclass(); + $this->assertEquals('', $error); } public function test_get_next_answerids(): void { @@ -795,4 +808,14 @@ class question_test extends \advanced_testcase { $newq->update_attempt_state_data_for_new_version($oldstep, $question) ); } + + public function test_helpers(): void { + $question = test_question_maker::make_question('ordering'); + $this->assertEquals(true, $question->is_complete_response([])); + $this->assertEquals(true, $question->is_gradable_response([])); + $this->assertEquals('', $question->get_validation_error([])); + + $this->expectException(\coding_exception::class); + qtype_ordering_question::get_types(['foo', 'bar', 'baz'], 'notexist'); + } }