Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
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 /** 18 * This file contains overall tests of multianswer questions. 19 * 20 * @package qtype 21 * @subpackage multianswer 22 * @copyright 2011 The Open University 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 require_once($CFG->dirroot . '/question/engine/tests/helpers.php'); 31 32 33 /** 34 * Unit tests for the multianswer question type. 35 * 36 * @copyright 2011 The Open University 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class qtype_multianswer_walkthrough_test extends qbehaviour_walkthrough_test_base { 40 41 protected function get_contains_subq_status(question_state $state) { 42 return new question_pattern_expectation('~' . 43 preg_quote($state->default_string(true), '~') . '<br />~'); 44 } 45 46 public function test_deferred_feedback() { 47 48 // Create a multianswer question. 49 $q = test_question_maker::make_question('multianswer', 'fourmc'); 50 $this->start_attempt_at_question($q, 'deferredfeedback', 4); 51 52 // Check the initial state. 53 $this->check_current_state(question_state::$todo); 54 $this->check_current_mark(null); 55 $this->check_current_output( 56 $this->get_contains_marked_out_of_summary(), 57 $this->get_does_not_contain_feedback_expectation(), 58 $this->get_does_not_contain_validation_error_expectation()); 59 60 // Save in incomplete answer. 61 $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '', 62 'sub3_answer' => '', 'sub4_answer' => '')); 63 64 // Verify. 65 $this->check_current_state(question_state::$invalid); 66 $this->check_current_mark(null); 67 $this->check_current_output( 68 $this->get_contains_marked_out_of_summary(), 69 $this->get_does_not_contain_feedback_expectation(), 70 $this->get_contains_validation_error_expectation()); 71 72 // Save a partially correct answer. 73 $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '1', 74 'sub3_answer' => '1', 'sub4_answer' => '1')); 75 76 // Verify. 77 $this->check_current_state(question_state::$complete); 78 $this->check_current_mark(null); 79 $this->check_current_output( 80 $this->get_contains_marked_out_of_summary(), 81 $this->get_does_not_contain_feedback_expectation(), 82 $this->get_does_not_contain_validation_error_expectation()); 83 84 // Now submit all and finish. 85 $this->finish(); 86 87 // Verify. 88 $this->check_current_state(question_state::$gradedpartial); 89 $this->check_current_mark(2); 90 $this->check_current_output( 91 $this->get_contains_mark_summary(2), 92 $this->get_contains_partcorrect_expectation(), 93 $this->get_does_not_contain_validation_error_expectation()); 94 } 95 96 public function test_deferred_feedback_numericalzero_not_answered() { 97 // Tests the situation found in MDL-35370. 98 99 // Create a multianswer question with one numerical subquestion, right answer zero. 100 $q = test_question_maker::make_question('multianswer', 'numericalzero'); 101 $this->start_attempt_at_question($q, 'deferredfeedback', 1); 102 103 // Check the initial state. 104 $this->check_current_state(question_state::$todo); 105 $this->check_current_mark(null); 106 $this->check_current_output( 107 $this->get_contains_marked_out_of_summary(), 108 $this->get_does_not_contain_feedback_expectation(), 109 $this->get_does_not_contain_validation_error_expectation()); 110 111 // Now submit all and finish. 112 $this->finish(); 113 114 // Verify. 115 $this->check_current_state(question_state::$gaveup); 116 $this->check_current_mark(null); 117 $this->check_current_output( 118 $this->get_contains_marked_out_of_summary(), 119 new question_pattern_expectation('~<input[^>]* class="[^"]*incorrect[^"]*" [^>]*/>~'), 120 $this->get_contains_subq_status(question_state::$gaveup), 121 $this->get_does_not_contain_validation_error_expectation()); 122 } 123 124 public function test_deferred_feedback_numericalzero_0_answer() { 125 // Tests the situation found in MDL-35370. 126 127 // Create a multianswer question with one numerical subquestion, right answer zero. 128 $q = test_question_maker::make_question('multianswer', 'numericalzero'); 129 $this->start_attempt_at_question($q, 'deferredfeedback', 1); 130 131 // Check the initial state. 132 $this->check_current_state(question_state::$todo); 133 $this->check_current_mark(null); 134 $this->check_current_output( 135 $this->get_contains_marked_out_of_summary(), 136 $this->get_does_not_contain_feedback_expectation(), 137 $this->get_does_not_contain_validation_error_expectation()); 138 139 // Save a the correct answer. 140 $this->process_submission(array('sub1_answer' => '0')); 141 142 // Verify. 143 $this->check_current_state(question_state::$complete); 144 $this->check_current_mark(null); 145 $this->check_current_output( 146 $this->get_contains_marked_out_of_summary(), 147 $this->get_does_not_contain_feedback_expectation(), 148 $this->get_does_not_contain_validation_error_expectation()); 149 150 // Now submit all and finish. 151 $this->finish(); 152 153 // Verify. 154 $this->check_current_state(question_state::$gradedright); 155 $this->check_current_mark(1); 156 $this->check_current_output( 157 $this->get_contains_mark_summary(1), 158 $this->get_contains_correct_expectation(), 159 $this->get_contains_subq_status(question_state::$gradedright), 160 $this->get_does_not_contain_validation_error_expectation()); 161 } 162 163 public function test_deferred_feedback_numericalzero_0_wrong() { 164 // Tests the situation found in MDL-35370. 165 166 // Create a multianswer question with one numerical subquestion, right answer zero. 167 $q = test_question_maker::make_question('multianswer', 'numericalzero'); 168 $this->start_attempt_at_question($q, 'deferredfeedback', 1); 169 170 // Check the initial state. 171 $this->check_current_state(question_state::$todo); 172 $this->check_current_mark(null); 173 $this->check_current_output( 174 $this->get_contains_marked_out_of_summary(), 175 $this->get_does_not_contain_feedback_expectation(), 176 $this->get_does_not_contain_validation_error_expectation()); 177 178 // Save a the correct answer. 179 $this->process_submission(array('sub1_answer' => '42')); 180 181 // Verify. 182 $this->check_current_state(question_state::$complete); 183 $this->check_current_mark(null); 184 $this->check_current_output( 185 $this->get_contains_marked_out_of_summary(), 186 $this->get_does_not_contain_feedback_expectation(), 187 $this->get_does_not_contain_validation_error_expectation()); 188 189 // Now submit all and finish. 190 $this->finish(); 191 192 // Verify. 193 $this->check_current_state(question_state::$gradedwrong); 194 $this->check_current_mark(0); 195 $this->check_current_output( 196 $this->get_contains_mark_summary(0), 197 $this->get_contains_incorrect_expectation(), 198 $this->get_contains_subq_status(question_state::$gradedwrong), 199 $this->get_does_not_contain_validation_error_expectation()); 200 } 201 202 public function test_interactive_feedback() { 203 204 // Create a multianswer question. 205 $q = test_question_maker::make_question('multianswer', 'fourmc'); 206 $q->hints = array( 207 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, true), 208 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 209 ); 210 $choices = array('0' => 'California', '1' => 'Arizona'); 211 212 $this->start_attempt_at_question($q, 'interactive', 4); 213 214 // Check the initial state. 215 $this->check_current_state(question_state::$todo); 216 $this->check_current_mark(null); 217 $this->assertEquals('interactivecountback', 218 $this->quba->get_question_attempt($this->slot)->get_behaviour_name()); 219 $this->check_current_output( 220 $this->get_contains_marked_out_of_summary(), 221 $this->get_contains_submit_button_expectation(true), 222 $this->get_does_not_contain_validation_error_expectation(), 223 $this->get_does_not_contain_feedback_expectation(), 224 $this->get_tries_remaining_expectation(3), 225 $this->get_does_not_contain_num_parts_correct(), 226 $this->get_no_hint_visible_expectation()); 227 $this->check_output_contains_selectoptions( 228 $this->get_contains_select_expectation('sub1_answer', $choices, null, true), 229 $this->get_contains_select_expectation('sub2_answer', $choices, null, true), 230 $this->get_contains_select_expectation('sub3_answer', $choices, null, true), 231 $this->get_contains_select_expectation('sub4_answer', $choices, null, true)); 232 233 // Submit a completely wrong response. 234 $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '0', 235 'sub3_answer' => '1', 'sub4_answer' => '0', '-submit' => 1)); 236 237 // Verify. 238 $this->check_current_state(question_state::$todo); 239 $this->check_current_mark(null); 240 $this->check_current_output( 241 $this->get_does_not_contain_num_parts_correct(), 242 $this->get_contains_hidden_expectation( 243 $this->quba->get_field_prefix($this->slot) . 'sub1_answer', ''), 244 $this->get_contains_hidden_expectation( 245 $this->quba->get_field_prefix($this->slot) . 'sub2_answer', ''), 246 $this->get_contains_hidden_expectation( 247 $this->quba->get_field_prefix($this->slot) . 'sub3_answer', ''), 248 $this->get_contains_hidden_expectation( 249 $this->quba->get_field_prefix($this->slot) . 'sub4_answer', ''), 250 $this->get_does_not_contain_submit_button_expectation(), 251 $this->get_contains_try_again_button_expectation(true), 252 $this->get_does_not_contain_correctness_expectation(), 253 $this->get_contains_hint_expectation('This is the first hint.')); 254 $this->check_output_contains_selectoptions( 255 $this->get_contains_select_expectation('sub1_answer', $choices, 1, false), 256 $this->get_contains_select_expectation('sub2_answer', $choices, 0, false), 257 $this->get_contains_select_expectation('sub3_answer', $choices, 1, false), 258 $this->get_contains_select_expectation('sub4_answer', $choices, 0, false)); 259 260 // Check that, if we review in this state, the try again button is disabled. 261 $displayoptions = new question_display_options(); 262 $displayoptions->readonly = true; 263 $html = $this->quba->render_question($this->slot, $displayoptions); 264 $this->assert($this->get_contains_try_again_button_expectation(false), $html); 265 266 // Try again. 267 $this->process_submission(array('sub1_answer' => '', 268 'sub2_answer' => '', 'sub3_answer' => '', 269 'sub4_answer' => '', '-tryagain' => 1)); 270 271 // Verify. 272 $this->check_current_state(question_state::$todo); 273 $this->check_current_mark(null); 274 $this->check_current_output( 275 $this->get_contains_submit_button_expectation(true), 276 $this->get_does_not_contain_feedback_expectation(), 277 $this->get_tries_remaining_expectation(2), 278 $this->get_no_hint_visible_expectation()); 279 $this->check_output_contains_selectoptions( 280 $this->get_contains_select_expectation('sub1_answer', $choices, null, true), 281 $this->get_contains_select_expectation('sub2_answer', $choices, null, true), 282 $this->get_contains_select_expectation('sub3_answer', $choices, null, true), 283 $this->get_contains_select_expectation('sub4_answer', $choices, null, true)); 284 285 // Submit a partially wrong response. 286 $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '1', 287 'sub3_answer' => '1', 'sub4_answer' => '1', '-submit' => 1)); 288 289 // Verify. 290 $this->check_current_state(question_state::$todo); 291 $this->check_current_mark(null); 292 $this->check_current_output( 293 $this->get_contains_num_parts_correct(2), 294 $this->get_contains_hidden_expectation( 295 $this->quba->get_field_prefix($this->slot) . 'sub1_answer', ''), 296 $this->get_contains_hidden_expectation( 297 $this->quba->get_field_prefix($this->slot) . 'sub2_answer', '1'), 298 $this->get_contains_hidden_expectation( 299 $this->quba->get_field_prefix($this->slot) . 'sub3_answer', ''), 300 $this->get_contains_hidden_expectation( 301 $this->quba->get_field_prefix($this->slot) . 'sub4_answer', '1'), 302 $this->get_does_not_contain_submit_button_expectation(), 303 $this->get_contains_hint_expectation('This is the second hint.')); 304 $this->check_output_contains_selectoptions( 305 $this->get_contains_select_expectation('sub1_answer', $choices, 1, false), 306 $this->get_contains_select_expectation('sub2_answer', $choices, 1, false), 307 $this->get_contains_select_expectation('sub3_answer', $choices, 1, false), 308 $this->get_contains_select_expectation('sub4_answer', $choices, 1, false)); 309 310 // Try again. 311 $this->process_submission(array('sub1_answer' => '', 312 'sub2_answer' => '1', 'sub3_answer' => '', 313 'sub4_answer' => '1', '-tryagain' => 1)); 314 315 // Verify. 316 $this->check_current_state(question_state::$todo); 317 $this->check_current_mark(null); 318 $this->check_current_output( 319 $this->get_contains_submit_button_expectation(true), 320 $this->get_does_not_contain_feedback_expectation(), 321 $this->get_tries_remaining_expectation(1), 322 $this->get_no_hint_visible_expectation()); 323 $this->check_output_contains_selectoptions( 324 $this->get_contains_select_expectation('sub1_answer', $choices, '', true), 325 $this->get_contains_select_expectation('sub2_answer', $choices, '1', true), 326 $this->get_contains_select_expectation('sub3_answer', $choices, '', true), 327 $this->get_contains_select_expectation('sub4_answer', $choices, '1', true)); 328 } 329 330 public function test_interactive_partial_response_does_not_reveal_answer() { 331 332 // Create a multianswer question. 333 $q = test_question_maker::make_question('multianswer', 'fourmc'); 334 $q->hints = array( 335 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, true), 336 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 337 ); 338 $choices = array('0' => 'California', '1' => 'Arizona'); 339 340 $this->start_attempt_at_question($q, 'interactive', 4); 341 342 // Check the initial state. 343 $this->check_current_state(question_state::$todo); 344 $this->check_current_mark(null); 345 $this->assertEquals('interactivecountback', 346 $this->quba->get_question_attempt($this->slot)->get_behaviour_name()); 347 $this->check_current_output( 348 $this->get_contains_marked_out_of_summary(), 349 $this->get_contains_submit_button_expectation(true), 350 $this->get_does_not_contain_validation_error_expectation(), 351 $this->get_does_not_contain_feedback_expectation(), 352 $this->get_tries_remaining_expectation(3), 353 $this->get_does_not_contain_num_parts_correct(), 354 $this->get_no_hint_visible_expectation()); 355 $this->check_output_contains_selectoptions( 356 $this->get_contains_select_expectation('sub1_answer', $choices, null, true), 357 $this->get_contains_select_expectation('sub2_answer', $choices, null, true), 358 $this->get_contains_select_expectation('sub3_answer', $choices, null, true), 359 $this->get_contains_select_expectation('sub4_answer', $choices, null, true)); 360 361 // Submit an incomplete response response. 362 $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '1', '-submit' => 1)); 363 364 // Verify. 365 $this->check_current_state(question_state::$invalid); 366 $this->check_current_mark(null); 367 $this->check_current_output( 368 $this->get_does_not_contain_num_parts_correct(), 369 $this->get_contains_validation_error_expectation(), 370 $this->get_contains_submit_button_expectation(true), 371 $this->get_does_not_contain_try_again_button_expectation(), 372 $this->get_does_not_contain_correctness_expectation(), 373 $this->get_no_hint_visible_expectation()); 374 $this->check_output_contains_selectoptions( 375 $this->get_contains_select_expectation('sub1_answer', $choices, 1, true), 376 $this->get_contains_select_expectation('sub2_answer', $choices, 1, true), 377 $this->get_contains_select_expectation('sub3_answer', $choices, null, true), 378 $this->get_contains_select_expectation('sub4_answer', $choices, null, true)); 379 $this->render(); 380 $a = array('mark' => '0.00', 'max' => '1.00'); 381 $this->assertNotRegExp('~' . preg_quote(get_string('markoutofmax', 'question', $a), '~') . '~', 382 $this->currentoutput); 383 $a['mark'] = '1.00'; 384 $this->assertNotRegExp('~' . preg_quote(get_string('markoutofmax', 'question', $a), '~') . '~', 385 $this->currentoutput); 386 } 387 388 public function test_interactivecountback_feedback() { 389 390 // Create a multianswer question. 391 $q = test_question_maker::make_question('multianswer', 'fourmc'); 392 $q->hints = array( 393 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, true, true), 394 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 395 ); 396 $choices = array('0' => 'California', '1' => 'Arizona'); 397 398 $this->start_attempt_at_question($q, 'interactive', 12); 399 400 // Check the initial state. 401 $this->check_current_state(question_state::$todo); 402 $this->check_current_mark(null); 403 $this->assertEquals('interactivecountback', 404 $this->quba->get_question_attempt($this->slot)->get_behaviour_name()); 405 $this->check_current_output( 406 $this->get_contains_marked_out_of_summary(), 407 $this->get_contains_submit_button_expectation(true), 408 $this->get_does_not_contain_validation_error_expectation(), 409 $this->get_does_not_contain_feedback_expectation(), 410 $this->get_tries_remaining_expectation(3), 411 $this->get_no_hint_visible_expectation()); 412 $this->check_output_contains_selectoptions( 413 $this->get_contains_select_expectation('sub1_answer', $choices, null, true), 414 $this->get_contains_select_expectation('sub2_answer', $choices, null, true), 415 $this->get_contains_select_expectation('sub3_answer', $choices, null, true), 416 $this->get_contains_select_expectation('sub4_answer', $choices, null, true)); 417 418 // Submit an answer with two right, and two wrong. 419 $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '1', 420 'sub3_answer' => '1', 'sub4_answer' => '1', '-submit' => 1)); 421 422 // Verify. 423 $this->check_current_state(question_state::$todo); 424 $this->check_current_mark(null); 425 $this->check_current_output( 426 $this->get_does_not_contain_submit_button_expectation(), 427 $this->get_contains_try_again_button_expectation(true), 428 $this->get_does_not_contain_correctness_expectation(), 429 new question_pattern_expectation('/Tries remaining: 2/'), 430 $this->get_contains_hint_expectation('This is the first hint.')); 431 $this->check_output_contains_selectoptions( 432 $this->get_contains_select_expectation('sub1_answer', $choices, 1, false), 433 $this->get_contains_select_expectation('sub2_answer', $choices, 1, false), 434 $this->get_contains_select_expectation('sub3_answer', $choices, 1, false), 435 $this->get_contains_select_expectation('sub4_answer', $choices, 1, false)); 436 437 // Check that extract responses will return the reset data. 438 $prefix = $this->quba->get_field_prefix($this->slot); 439 $this->assertEquals(array('sub1_answer' => 1), 440 $this->quba->extract_responses($this->slot, array($prefix . 'sub1_answer' => 1))); 441 442 // Do try again. 443 $this->process_submission(array('sub1_answer' => '', 444 'sub2_answer' => '1', 'sub3_answer' => '', 445 'sub4_answer' => '1', '-tryagain' => 1)); 446 447 // Verify. 448 $this->check_current_state(question_state::$todo); 449 $this->check_current_mark(null); 450 $this->check_current_output( 451 $this->get_contains_submit_button_expectation(true), 452 $this->get_does_not_contain_feedback_expectation(), 453 $this->get_tries_remaining_expectation(2), 454 $this->get_no_hint_visible_expectation()); 455 $this->check_output_contains_selectoptions( 456 $this->get_contains_select_expectation('sub1_answer', $choices, '', true), 457 $this->get_contains_select_expectation('sub2_answer', $choices, '1', true), 458 $this->get_contains_select_expectation('sub3_answer', $choices, '', true), 459 $this->get_contains_select_expectation('sub4_answer', $choices, '1', true)); 460 461 // Submit the right answer. 462 $this->process_submission(array('sub1_answer' => '0', 'sub2_answer' => '1', 463 'sub3_answer' => '0', 'sub4_answer' => '1', '-submit' => 1)); 464 465 // Verify. 466 $this->check_current_state(question_state::$gradedright); 467 $this->check_current_mark(10); 468 $this->check_current_output( 469 $this->get_does_not_contain_submit_button_expectation(), 470 $this->get_does_not_contain_try_again_button_expectation(), 471 $this->get_contains_correct_expectation(), 472 new question_no_pattern_expectation('/class="control\b[^"]*\bpartiallycorrect"/')); 473 $this->check_output_contains_selectoptions( 474 $this->get_contains_select_expectation('sub1_answer', $choices, '0', false), 475 $this->get_contains_select_expectation('sub2_answer', $choices, '1', false), 476 $this->get_contains_select_expectation('sub3_answer', $choices, '0', false), 477 $this->get_contains_select_expectation('sub4_answer', $choices, '1', false)); 478 } 479 480 public function test_deferred_feedback_multiple() { 481 482 // Create a multianswer question. 483 $q = test_question_maker::make_question('multianswer', 'multiple'); 484 $this->start_attempt_at_question($q, 'deferredfeedback', 2); 485 486 // Check the initial state. 487 $this->check_current_state(question_state::$todo); 488 $this->check_current_mark(null); 489 $this->check_current_output( 490 $this->get_contains_marked_out_of_summary(), 491 $this->get_does_not_contain_feedback_expectation(), 492 $this->get_does_not_contain_validation_error_expectation()); 493 494 // Save in incomplete answer. 495 $this->process_submission(array('sub1_choice0' => '1', 'sub1_choice1' => '1', 496 'sub1_choice2' => '', 'sub1_choice3' => '', 497 'sub1_choice4' => '', 'sub1_choice5' => '1', 498 )); 499 500 // Verify. 501 $this->check_current_state(question_state::$invalid); 502 $this->check_current_mark(null); 503 $this->check_current_output( 504 $this->get_contains_marked_out_of_summary(), 505 $this->get_does_not_contain_feedback_expectation(), 506 $this->get_contains_validation_error_expectation()); 507 508 // Save a partially correct answer. 509 $this->process_submission(array('sub1_choice0' => '1', 'sub1_choice1' => '', 510 'sub1_choice2' => '', 'sub1_choice3' => '', 511 'sub1_choice4' => '1', 'sub1_choice5' => '1', 512 'sub2_choice0' => '', 'sub2_choice1' => '', 513 'sub2_choice2' => '', 'sub2_choice3' => '', 514 'sub2_choice4' => '1', 515 )); 516 517 // Verify. 518 $this->check_current_state(question_state::$complete); 519 $this->check_current_mark(null); 520 $this->check_current_output( 521 $this->get_contains_marked_out_of_summary(), 522 $this->get_does_not_contain_feedback_expectation(), 523 $this->get_does_not_contain_validation_error_expectation()); 524 525 // Now submit all and finish. 526 $this->finish(); 527 528 // Verify. 529 $this->check_current_state(question_state::$gradedpartial); 530 $this->check_current_mark(1.5); 531 $this->check_current_output( 532 $this->get_contains_mark_summary(1.5), 533 $this->get_contains_partcorrect_expectation(), 534 $this->get_does_not_contain_validation_error_expectation()); 535 } 536 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body