See Release Notes
Long Term Support Release
Differences Between: [Versions 311 and 401] [Versions 400 and 401]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace qtype_multichoice; 18 19 use qtype_multichoice; 20 use qtype_multichoice_edit_form; 21 use question_possible_response; 22 23 defined('MOODLE_INTERNAL') || die(); 24 25 global $CFG; 26 require_once($CFG->dirroot . '/question/engine/tests/helpers.php'); 27 require_once($CFG->dirroot . '/question/type/multichoice/questiontype.php'); 28 require_once($CFG->dirroot . '/question/type/edit_question_form.php'); 29 require_once($CFG->dirroot . '/question/type/multichoice/edit_multichoice_form.php'); 30 31 /** 32 * Unit tests for the multiple choice question definition class. 33 * 34 * @package qtype_multichoice 35 * @copyright 2009 The Open University 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 * @covers \qtype_multichoice 38 */ 39 class question_type_test extends \advanced_testcase { 40 protected $qtype; 41 42 protected function setUp(): void { 43 $this->qtype = new qtype_multichoice(); 44 } 45 46 protected function tearDown(): void { 47 $this->qtype = null; 48 } 49 50 public function test_name() { 51 $this->assertEquals($this->qtype->name(), 'multichoice'); 52 } 53 54 protected function get_test_question_data() { 55 $q = new \stdClass(); 56 $q->id = 1; 57 $q->options = new \stdClass(); 58 $q->options->single = true; 59 $q->options->answers[1] = (object) array('answer' => 'frog', 60 'answerformat' => FORMAT_HTML, 'fraction' => 1); 61 $q->options->answers[2] = (object) array('answer' => 'toad', 62 'answerformat' => FORMAT_HTML, 'fraction' => 0); 63 64 return $q; 65 } 66 67 public function test_can_analyse_responses() { 68 $this->assertTrue($this->qtype->can_analyse_responses()); 69 } 70 71 public function test_get_random_guess_score() { 72 $q = $this->get_test_question_data(); 73 $this->assertEquals(0.5, $this->qtype->get_random_guess_score($q)); 74 } 75 76 public function test_get_random_guess_score_broken_question() { 77 $q = $this->get_test_question_data(); 78 $q->options->answers = []; 79 $this->assertNull($this->qtype->get_random_guess_score($q)); 80 } 81 82 public function test_get_random_guess_score_multi() { 83 $q = $this->get_test_question_data(); 84 $q->options->single = false; 85 $this->assertNull($this->qtype->get_random_guess_score($q)); 86 } 87 88 public function test_get_possible_responses_single() { 89 $q = $this->get_test_question_data(); 90 $responses = $this->qtype->get_possible_responses($q); 91 92 $this->assertEquals(array( 93 $q->id => array( 94 1 => new question_possible_response('frog', 1), 95 2 => new question_possible_response('toad', 0), 96 null => question_possible_response::no_response(), 97 )), $this->qtype->get_possible_responses($q)); 98 } 99 100 public function test_get_possible_responses_multi() { 101 $q = $this->get_test_question_data(); 102 $q->options->single = false; 103 104 $this->assertEquals(array( 105 1 => array(1 => new question_possible_response('frog', 1)), 106 2 => array(2 => new question_possible_response('toad', 0)), 107 ), $this->qtype->get_possible_responses($q)); 108 } 109 110 public function get_question_saving_which() { 111 return array(array('two_of_four'), array('one_of_four')); 112 } 113 114 /** 115 * @dataProvider get_question_saving_which 116 */ 117 public function test_question_saving_two_of_four($which) { 118 $this->resetAfterTest(true); 119 $this->setAdminUser(); 120 121 $questiondata = \test_question_maker::get_question_data('multichoice', $which); 122 $formdata = \test_question_maker::get_question_form_data('multichoice', $which); 123 124 $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); 125 $cat = $generator->create_question_category(array()); 126 127 $formdata->category = "{$cat->id},{$cat->contextid}"; 128 qtype_multichoice_edit_form::mock_submit((array)$formdata); 129 130 $form = \qtype_multichoice_test_helper::get_question_editing_form($cat, $questiondata); 131 132 $this->assertTrue($form->is_validated()); 133 134 $fromform = $form->get_data(); 135 136 $returnedfromsave = $this->qtype->save_question($questiondata, $fromform); 137 $actualquestionsdata = question_load_questions([$returnedfromsave->id], 'qbe.idnumber'); 138 $actualquestiondata = end($actualquestionsdata); 139 140 foreach ($questiondata as $property => $value) { 141 if (!in_array($property, ['id', 'timemodified', 'timecreated', 'options', 'hints', 'stamp', 142 'versionid', 'questionbankentryid'])) { 143 $this->assertEquals($value, $actualquestiondata->$property); 144 } 145 } 146 147 foreach ($questiondata->options as $optionname => $value) { 148 if ($optionname != 'answers') { 149 $this->assertEquals($value, $actualquestiondata->options->$optionname); 150 } 151 } 152 153 foreach ($questiondata->hints as $hint) { 154 $actualhint = array_shift($actualquestiondata->hints); 155 foreach ($hint as $property => $value) { 156 if (!in_array($property, array('id', 'questionid', 'options'))) { 157 $this->assertEquals($value, $actualhint->$property); 158 } 159 } 160 } 161 162 foreach ($questiondata->options->answers as $answer) { 163 $actualanswer = array_shift($actualquestiondata->options->answers); 164 foreach ($answer as $ansproperty => $ansvalue) { 165 // This question does not use 'answerformat', will ignore it. 166 if (!in_array($ansproperty, array('id', 'question', 'answerformat'))) { 167 $this->assertEquals($ansvalue, $actualanswer->$ansproperty); 168 } 169 } 170 } 171 } 172 173 /** 174 * Test to make sure that loading of question options works, including in an error case. 175 */ 176 public function test_get_question_options() { 177 global $DB; 178 179 $this->resetAfterTest(true); 180 $this->setAdminUser(); 181 182 // Create a complete, in DB question to use. 183 $questiondata = \test_question_maker::get_question_data('multichoice', 'two_of_four'); 184 $formdata = \test_question_maker::get_question_form_data('multichoice', 'two_of_four'); 185 186 $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); 187 $cat = $generator->create_question_category(array()); 188 189 $formdata->category = "{$cat->id},{$cat->contextid}"; 190 qtype_multichoice_edit_form::mock_submit((array)$formdata); 191 192 $form = \qtype_multichoice_test_helper::get_question_editing_form($cat, $questiondata); 193 194 $this->assertTrue($form->is_validated()); 195 196 $fromform = $form->get_data(); 197 198 $returnedfromsave = $this->qtype->save_question($questiondata, $fromform); 199 200 // Now get just the raw DB record. 201 $question = $DB->get_record('question', ['id' => $returnedfromsave->id], '*', MUST_EXIST); 202 203 // Load it. 204 $this->qtype->get_question_options($question); 205 $this->assertDebuggingNotCalled(); 206 $this->assertInstanceOf(\stdClass::class, $question->options); 207 208 $options = $question->options; 209 $this->assertEquals($question->id, $options->questionid); 210 $this->assertEquals(0, $options->single); 211 212 $this->assertCount(4, $options->answers); 213 214 // Now we are going to delete the options record. 215 $DB->delete_records('qtype_multichoice_options', ['questionid' => $question->id]); 216 217 // Now see what happens. 218 $question = $DB->get_record('question', ['id' => $returnedfromsave->id], '*', MUST_EXIST); 219 $this->qtype->get_question_options($question); 220 221 $this->assertDebuggingCalled('Question ID '.$question->id.' was missing an options record. Using default.'); 222 $this->assertInstanceOf(\stdClass::class, $question->options); 223 $options = $question->options; 224 $this->assertEquals($question->id, $options->questionid); 225 $this->assertCount(4, $options->answers); 226 227 $this->assertEquals(get_string('correctfeedbackdefault', 'question'), $options->correctfeedback); 228 $this->assertEquals(FORMAT_HTML, $options->correctfeedbackformat); 229 230 // We no longer know how many answers, so it just has to guess with the default value. 231 $this->assertEquals(get_config('qtype_multichoice', 'answerhowmany'), $options->single); 232 233 // And finally we try again with no answer either. 234 $DB->delete_records('question_answers', ['question' => $question->id]); 235 236 $question = $DB->get_record('question', ['id' => $returnedfromsave->id], '*', MUST_EXIST); 237 $this->qtype->get_question_options($question); 238 239 $this->assertDebuggingCalled('Question ID '.$question->id.' was missing an options record. Using default.'); 240 $this->assertInstanceOf(\stdClass::class, $question->options); 241 $options = $question->options; 242 $this->assertEquals($question->id, $options->questionid); 243 $this->assertCount(0, $options->answers); 244 } 245 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body