Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 tests that walks a question through the deferred feedback
  19   * behaviour.
  20   *
  21   * @package    qbehaviour
  22   * @subpackage deferredfeedback
  23   * @copyright  2009 The Open University
  24   * @license  http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  
  30  global $CFG;
  31  require_once (__DIR__ . '/../../../engine/lib.php');
  32  require_once (__DIR__ . '/../../../engine/tests/helpers.php');
  33  
  34  
  35  /**
  36   * Unit tests for the deferred feedback behaviour.
  37   *
  38   * @copyright  2009 The Open University
  39   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class qbehaviour_deferredfeedback_walkthrough_test extends qbehaviour_walkthrough_test_base {
  42      public function test_deferredfeedback_feedback_truefalse() {
  43  
  44          // Create a true-false question with correct answer true.
  45          $tf = test_question_maker::make_question('truefalse', 'true');
  46          $this->start_attempt_at_question($tf, 'deferredfeedback', 2);
  47  
  48          // Check the initial state.
  49          $this->check_current_state(question_state::$todo);
  50          $this->check_output_contains_lang_string('notyetanswered', 'question');
  51          $this->check_current_mark(null);
  52          $this->check_current_output($this->get_contains_question_text_expectation($tf),
  53                  $this->get_does_not_contain_feedback_expectation());
  54          $this->assertEquals(get_string('true', 'qtype_truefalse'),
  55                  $this->quba->get_right_answer_summary($this->slot));
  56          $this->assertRegExp('/' . preg_quote($tf->questiontext, '/') . '/',
  57                  $this->quba->get_question_summary($this->slot));
  58          $this->assertNull($this->quba->get_response_summary($this->slot));
  59  
  60          // Process a true answer and check the expected result.
  61          $this->process_submission(array('answer' => 1));
  62  
  63          $this->check_current_state(question_state::$complete);
  64          $this->check_output_contains_lang_string('answersaved', 'question');
  65          $this->check_current_mark(null);
  66          $this->check_current_output($this->get_contains_tf_true_radio_expectation(true, true),
  67                  $this->get_does_not_contain_correctness_expectation(),
  68                  $this->get_does_not_contain_feedback_expectation());
  69  
  70          // Process the same data again, check it does not create a new step.
  71          $numsteps = $this->get_step_count();
  72          $this->process_submission(array('answer' => 1));
  73          $this->check_step_count($numsteps);
  74  
  75          // Process different data, check it creates a new step.
  76          $this->process_submission(array('answer' => 0));
  77          $this->check_step_count($numsteps + 1);
  78          $this->check_current_state(question_state::$complete);
  79  
  80          // Change back, check it creates a new step.
  81          $this->process_submission(array('answer' => 1));
  82          $this->check_step_count($numsteps + 2);
  83  
  84          // Finish the attempt.
  85          $this->quba->finish_all_questions();
  86  
  87          // Verify.
  88          $this->check_current_state(question_state::$gradedright);
  89          $this->check_current_mark(2);
  90          $this->check_current_output($this->get_contains_correct_expectation(),
  91                  $this->get_contains_tf_true_radio_expectation(false, true),
  92                  new question_pattern_expectation('/class="r0 correct"/'));
  93          $this->assertEquals(get_string('true', 'qtype_truefalse'),
  94                  $this->quba->get_response_summary($this->slot));
  95  
  96          // Process a manual comment.
  97          $this->manual_grade('Not good enough!', 1, FORMAT_HTML);
  98  
  99          $this->check_current_state(question_state::$mangrpartial);
 100          $this->check_current_mark(1);
 101          $this->check_current_output(
 102                  new question_pattern_expectation('/' . preg_quote('Not good enough!', '/') . '/'));
 103  
 104          // Now change the correct answer to the question, and regrade.
 105          $tf->rightanswer = false;
 106          $this->quba->regrade_all_questions();
 107  
 108          // Verify.
 109          $this->check_current_state(question_state::$mangrpartial);
 110          $this->check_current_mark(1);
 111  
 112          $autogradedstep = $this->get_step($this->get_step_count() - 2);
 113          $this->assertEquals($autogradedstep->get_fraction(), 0, '', 0.0000001);
 114      }
 115  
 116      public function test_deferredfeedback_feedback_multichoice_single() {
 117  
 118          // Create a true-false question with correct answer true.
 119          $mc = test_question_maker::make_a_multichoice_single_question();
 120          $this->start_attempt_at_question($mc, 'deferredfeedback', 3);
 121  
 122          // Start a deferred feedback attempt and add the question to it.
 123          $rightindex = $this->get_mc_right_answer_index($mc);
 124  
 125          $this->check_current_state(question_state::$todo);
 126          $this->check_output_contains_lang_string('notyetanswered', 'question');
 127          $this->check_current_mark(null);
 128          $this->check_current_output(
 129                  $this->get_contains_question_text_expectation($mc),
 130                  $this->get_contains_mc_radio_expectation(0, true, false),
 131                  $this->get_contains_mc_radio_expectation(1, true, false),
 132                  $this->get_contains_mc_radio_expectation(2, true, false),
 133                  $this->get_does_not_contain_feedback_expectation());
 134  
 135          // Process the data extracted for this question.
 136          $this->process_submission(array('answer' => $rightindex));
 137  
 138          // Verify.
 139          $this->check_current_state(question_state::$complete);
 140          $this->check_output_contains_lang_string('answersaved', 'question');
 141          $this->check_current_mark(null);
 142          $this->check_current_output(
 143                  $this->get_contains_mc_radio_expectation($rightindex, true, true),
 144                  $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, true, false),
 145                  $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, true, false),
 146                  $this->get_does_not_contain_correctness_expectation(),
 147                  $this->get_does_not_contain_feedback_expectation());
 148  
 149          // Finish the attempt.
 150          $this->quba->finish_all_questions();
 151  
 152          // Verify.
 153          $this->check_current_state(question_state::$gradedright);
 154          $this->check_current_mark(3);
 155          $this->check_current_output(
 156                  $this->get_contains_mc_radio_expectation($rightindex, false, true),
 157                  $this->get_contains_correct_expectation());
 158  
 159          // Now change the correct answer to the question, and regrade.
 160          $mc->answers[13]->fraction = -0.33333333;
 161          $mc->answers[14]->fraction = 1;
 162          $this->quba->regrade_all_questions();
 163  
 164          // Verify.
 165          $this->check_current_state(question_state::$gradedwrong);
 166          $this->check_current_mark(-1);
 167          $this->check_current_output(
 168                  $this->get_contains_incorrect_expectation());
 169      }
 170  
 171      public function test_deferredfeedback_resume_multichoice_single() {
 172  
 173          // Create a multiple-choice question.
 174          $mc = test_question_maker::make_a_multichoice_single_question();
 175  
 176          // Attempt it getting it wrong.
 177          $this->start_attempt_at_question($mc, 'deferredfeedback', 3);
 178          $rightindex = $this->get_mc_right_answer_index($mc);
 179          $wrongindex = ($rightindex + 1) % 3;
 180  
 181          $this->check_current_state(question_state::$todo);
 182          $this->check_output_contains_lang_string('notyetanswered', 'question');
 183          $this->check_current_mark(null);
 184          $this->process_submission(array('answer' => $wrongindex));
 185          $this->quba->finish_all_questions();
 186  
 187          // Verify.
 188          $this->check_current_state(question_state::$gradedwrong);
 189          $this->check_current_mark(-1);
 190          $this->check_current_output(
 191                  $this->get_contains_mc_radio_expectation($wrongindex, false, true),
 192                  $this->get_contains_incorrect_expectation());
 193  
 194          // Save the old attempt.
 195          $oldqa = $this->quba->get_question_attempt($this->slot);
 196  
 197          // Reinitialise.
 198          $this->setUp();
 199          $this->quba->set_preferred_behaviour('deferredfeedback');
 200          $this->slot = $this->quba->add_question($mc, 3);
 201          $this->quba->start_question_based_on($this->slot, $oldqa);
 202  
 203          // Verify.
 204          $this->check_current_state(question_state::$complete);
 205          $this->check_output_contains_lang_string('notchanged', 'question');
 206          $this->check_current_mark(null);
 207          $this->check_current_output(
 208                  $this->get_contains_mc_radio_expectation($wrongindex, true, true),
 209                  $this->get_does_not_contain_feedback_expectation(),
 210                  $this->get_does_not_contain_correctness_expectation());
 211  
 212          // Now get it right.
 213          $this->process_submission(array('answer' => $rightindex));
 214          $this->quba->finish_all_questions();
 215  
 216          // Verify.
 217          $this->check_current_state(question_state::$gradedright);
 218          $this->check_current_mark(3);
 219          $this->check_current_output(
 220                  $this->get_contains_mc_radio_expectation($rightindex, false, true),
 221                  $this->get_contains_correct_expectation());
 222      }
 223  
 224      public function test_deferredfeedback_resume_multichoice_single_emptyanswer_first() {
 225  
 226          // Create a multiple-choice question.
 227          $mc = test_question_maker::make_a_multichoice_single_question();
 228  
 229          // Attempt it and submit empty.
 230          $this->start_attempt_at_question($mc, 'deferredfeedback', 3);
 231          $rightindex = $this->get_mc_right_answer_index($mc);
 232          $wrongindex = ($rightindex + 1) % 3;
 233  
 234          $this->check_current_state(question_state::$todo);
 235          $this->check_output_contains_lang_string('notyetanswered', 'question');
 236          $this->check_current_mark(null);
 237          $this->process_submission(array('-submit' => 1));
 238          $this->quba->finish_all_questions();
 239  
 240          // Verify.
 241          $this->check_current_state(question_state::$gaveup);
 242          $this->check_current_mark(null);
 243          $this->check_current_output(
 244                  $this->get_contains_mc_radio_expectation(0, false, false),
 245                  $this->get_contains_mc_radio_expectation(1, false, false),
 246                  $this->get_contains_mc_radio_expectation(2, false, false),
 247                  $this->get_contains_general_feedback_expectation($mc));
 248  
 249          // Save the old attempt.
 250          $oldqa = $this->quba->get_question_attempt($this->slot);
 251  
 252          // Reinitialise.
 253          $this->setUp();
 254          $this->quba->set_preferred_behaviour('deferredfeedback');
 255          $this->slot = $this->quba->add_question($mc, 3);
 256          $this->quba->start_question_based_on($this->slot, $oldqa);
 257  
 258          // Verify.
 259          $this->check_current_state(question_state::$todo);
 260          $this->check_output_contains_lang_string('notyetanswered', 'question');
 261          $this->check_current_mark(null);
 262          $this->check_current_output(
 263                  $this->get_contains_mc_radio_expectation(0, true, false),
 264                  $this->get_contains_mc_radio_expectation(1, true, false),
 265                  $this->get_contains_mc_radio_expectation(2, true, false),
 266                  $this->get_does_not_contain_feedback_expectation(),
 267                  $this->get_does_not_contain_correctness_expectation());
 268  
 269          // Now get it wrong.
 270          $this->process_submission(array('answer' => $wrongindex));
 271          $this->quba->finish_all_questions();
 272  
 273          // Verify.
 274          $this->check_current_state(question_state::$gradedwrong);
 275          $this->check_current_mark(-1);
 276          $this->check_current_output(
 277                  $this->get_contains_mc_radio_expectation($wrongindex, false, true),
 278                  $this->get_contains_incorrect_expectation());
 279  
 280          // Save the old attempt.
 281          $oldqa = $this->quba->get_question_attempt($this->slot);
 282  
 283          // Reinitialise.
 284          $this->setUp();
 285          $this->quba->set_preferred_behaviour('deferredfeedback');
 286          $this->slot = $this->quba->add_question($mc, 3);
 287          $this->quba->start_question_based_on($this->slot, $oldqa);
 288  
 289          // Verify.
 290          $this->check_current_state(question_state::$complete);
 291          $this->check_output_contains_lang_string('notchanged', 'question');
 292          $this->check_current_mark(null);
 293          $this->check_current_output(
 294                  $this->get_contains_mc_radio_expectation($wrongindex, true, true),
 295                  $this->get_does_not_contain_feedback_expectation(),
 296                  $this->get_does_not_contain_correctness_expectation());
 297  
 298          // Now get it right.
 299          $this->process_submission(array('answer' => $rightindex));
 300          $this->quba->finish_all_questions();
 301  
 302          // Verify.
 303          $this->check_current_state(question_state::$gradedright);
 304          $this->check_current_mark(3);
 305          $this->check_current_output(
 306                  $this->get_contains_mc_radio_expectation($rightindex, false, true),
 307                  $this->get_contains_correct_expectation());
 308      }
 309  }