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   * with certainty base marking behaviour.
  20   *
  21   * @package    qbehaviour
  22   * @subpackage deferredcbm
  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 with certainty base marking 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_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_test_base {
  42      public function test_deferred_cbm_truefalse_high_certainty() {
  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, 'deferredcbm', 2);
  47  
  48          // Verify.
  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(
  53                  $this->get_contains_question_text_expectation($tf),
  54                  $this->get_contains_tf_true_radio_expectation(true, false),
  55                  $this->get_contains_tf_false_radio_expectation(true, false),
  56                  $this->get_contains_cbm_radio_expectation(1, true, false),
  57                  $this->get_contains_cbm_radio_expectation(2, true, false),
  58                  $this->get_contains_cbm_radio_expectation(3, true, false),
  59                  $this->get_does_not_contain_feedback_expectation());
  60  
  61          // Process the data extracted for this question.
  62          $this->process_submission(array('answer' => 1, '-certainty' => 3));
  63  
  64          // Verify.
  65          $this->check_current_state(question_state::$complete);
  66          $this->check_output_contains_lang_string('answersaved', 'question');
  67          $this->check_current_mark(null);
  68          $this->check_current_output(
  69                  $this->get_contains_tf_true_radio_expectation(true, true),
  70                  $this->get_contains_cbm_radio_expectation(3, true, true),
  71                  $this->get_does_not_contain_correctness_expectation(),
  72                  $this->get_does_not_contain_feedback_expectation());
  73  
  74          // Process the same data again, check it does not create a new step.
  75          $numsteps = $this->get_step_count();
  76          $this->process_submission(array('answer' => 1, '-certainty' => 3));
  77          $this->check_step_count($numsteps);
  78  
  79          // Process different data, check it creates a new step.
  80          $this->process_submission(array('answer' => 1, '-certainty' => 1));
  81          $this->check_step_count($numsteps + 1);
  82          $this->check_current_state(question_state::$complete);
  83  
  84          // Change back, check it creates a new step.
  85          $this->process_submission(array('answer' => 1, '-certainty' => 3));
  86          $this->check_step_count($numsteps + 2);
  87  
  88          // Finish the attempt.
  89          $this->quba->finish_all_questions();
  90  
  91          // Verify.
  92          $this->check_current_state(question_state::$gradedright);
  93          $this->check_current_mark(6);
  94          $this->check_current_output(
  95                  $this->get_contains_tf_true_radio_expectation(false, true),
  96                  $this->get_contains_cbm_radio_expectation(3, false, true),
  97                  $this->get_contains_correct_expectation());
  98  
  99          // Process a manual comment.
 100          $this->manual_grade('Not good enough!', 5, FORMAT_HTML);
 101  
 102          // Verify.
 103          $this->check_current_state(question_state::$mangrright);
 104          $this->check_current_mark(5);
 105          $this->check_current_output(new question_pattern_expectation('/' .
 106                  preg_quote('Not good enough!', '/') . '/'));
 107  
 108          // Now change the correct answer to the question, and regrade.
 109          $tf->rightanswer = false;
 110          $this->quba->regrade_all_questions();
 111  
 112          // Verify.
 113          $this->check_current_state(question_state::$mangrright);
 114          $this->check_current_mark(5);
 115          $autogradedstep = $this->get_step($this->get_step_count() - 2);
 116          $this->assertEquals(-6, $autogradedstep->get_fraction(), '', 0.0000001);
 117      }
 118  
 119      public function test_deferred_cbm_truefalse_low_certainty() {
 120  
 121          // Create a true-false question with correct answer true.
 122          $tf = test_question_maker::make_question('truefalse', 'true');
 123          $this->start_attempt_at_question($tf, 'deferredcbm', 2);
 124  
 125          // Verify.
 126          $this->check_current_state(question_state::$todo);
 127          $this->check_output_contains_lang_string('notyetanswered', 'question');
 128          $this->check_current_mark(null);
 129          $this->check_current_output(
 130                  $this->get_does_not_contain_correctness_expectation(),
 131                  $this->get_contains_cbm_radio_expectation(1, true, false),
 132                  $this->get_does_not_contain_feedback_expectation());
 133  
 134          // Submit ansewer with low certainty.
 135          $this->process_submission(array('answer' => 1, '-certainty' => 1));
 136  
 137          // Verify.
 138          $this->check_current_state(question_state::$complete);
 139          $this->check_output_contains_lang_string('answersaved', 'question');
 140          $this->check_current_mark(null);
 141          $this->check_current_output($this->get_does_not_contain_correctness_expectation(),
 142                  $this->get_contains_cbm_radio_expectation(1, true, true),
 143                  $this->get_does_not_contain_feedback_expectation());
 144  
 145          // Finish the attempt.
 146          $this->quba->finish_all_questions();
 147  
 148          // Verify.
 149          $this->check_current_state(question_state::$gradedright);
 150          $this->check_current_mark(2);
 151          $this->check_current_output($this->get_contains_correct_expectation(),
 152                  $this->get_contains_cbm_radio_expectation(1, false, true));
 153          $this->assertEquals(get_string('true', 'qtype_truefalse') . ' [' .
 154                  question_cbm::get_short_string(question_cbm::LOW) . ']',
 155                  $this->quba->get_response_summary($this->slot));
 156      }
 157  
 158      public function test_deferred_cbm_truefalse_default_certainty() {
 159  
 160          // Create a true-false question with correct answer true.
 161          $tf = test_question_maker::make_question('truefalse', 'true');
 162          $this->start_attempt_at_question($tf, 'deferredcbm', 2);
 163  
 164          // Verify.
 165          $this->check_current_state(question_state::$todo);
 166          $this->check_output_contains_lang_string('notyetanswered', 'question');
 167          $this->check_current_mark(null);
 168          $this->check_current_output(
 169                  $this->get_does_not_contain_correctness_expectation(),
 170                  $this->get_contains_cbm_radio_expectation(1, true, false),
 171                  $this->get_does_not_contain_feedback_expectation());
 172  
 173          // Submit ansewer with low certainty and finish the attempt.
 174          $this->process_submission(array('answer' => 1));
 175          $this->quba->finish_all_questions();
 176  
 177          // Verify.
 178          $qa = $this->quba->get_question_attempt($this->slot);
 179          $this->check_current_state(question_state::$gradedright);
 180          $this->check_current_mark(2);
 181          $this->check_current_output($this->get_contains_correct_expectation(),
 182                  $this->get_contains_cbm_radio_expectation(1, false, false),
 183                  new question_pattern_expectation('/' . preg_quote(
 184                          get_string('assumingcertainty', 'qbehaviour_deferredcbm',
 185                          question_cbm::get_string(
 186                              $qa->get_last_behaviour_var('_assumedcertainty'))), '/') . '/'));
 187          $this->assertEquals(get_string('true', 'qtype_truefalse'),
 188                  $this->quba->get_response_summary($this->slot));
 189      }
 190  
 191      public function test_deferredcbm_resume_multichoice_single() {
 192  
 193          // Create a multiple-choice question.
 194          $mc = test_question_maker::make_a_multichoice_single_question();
 195  
 196          // Attempt it getting it wrong.
 197          $this->start_attempt_at_question($mc, 'deferredcbm', 1);
 198          $rightindex = $this->get_mc_right_answer_index($mc);
 199          $wrongindex = ($rightindex + 1) % 3;
 200          $this->process_submission(array('answer' => $wrongindex, '-certainty' => 2));
 201          $this->quba->finish_all_questions();
 202  
 203          // Verify.
 204          $this->check_current_state(question_state::$gradedwrong);
 205          $this->check_current_mark(-2);
 206          $this->check_current_output(
 207                  $this->get_contains_mc_radio_expectation($wrongindex, false, true),
 208                  $this->get_contains_cbm_radio_expectation(2, false, true),
 209                  $this->get_contains_incorrect_expectation());
 210          $this->assertEquals('A [' . question_cbm::get_short_string(question_cbm::HIGH) . ']',
 211                  $this->quba->get_right_answer_summary($this->slot));
 212          $this->assertRegExp('/' . preg_quote($mc->questiontext, '/') . '/',
 213                  $this->quba->get_question_summary($this->slot));
 214          $this->assertRegExp('/(B|C) \[' . preg_quote(question_cbm::get_short_string(question_cbm::MED), '/') . '\]/',
 215                  $this->quba->get_response_summary($this->slot));
 216  
 217          // Save the old attempt.
 218          $oldqa = $this->quba->get_question_attempt($this->slot);
 219  
 220          // Reinitialise.
 221          $this->setUp();
 222          $this->quba->set_preferred_behaviour('deferredcbm');
 223          $this->slot = $this->quba->add_question($mc, 1);
 224          $this->quba->start_question_based_on($this->slot, $oldqa);
 225  
 226          // Verify.
 227          $this->check_current_state(question_state::$complete);
 228          $this->check_output_contains_lang_string('notchanged', 'question');
 229          $this->check_current_mark(null);
 230          $this->check_current_output(
 231                  $this->get_contains_mc_radio_expectation($wrongindex, true, true),
 232                  $this->get_contains_cbm_radio_expectation(2, true, true),
 233                  $this->get_does_not_contain_feedback_expectation(),
 234                  $this->get_does_not_contain_correctness_expectation());
 235          $this->assertEquals('A [' . question_cbm::get_short_string(question_cbm::HIGH) . ']',
 236                  $this->quba->get_right_answer_summary($this->slot));
 237          $this->assertRegExp('/' . preg_quote($mc->questiontext, '/') . '/',
 238                  $this->quba->get_question_summary($this->slot));
 239          $this->assertNull($this->quba->get_response_summary($this->slot));
 240  
 241          // Now get it right.
 242          $this->process_submission(array('answer' => $rightindex, '-certainty' => 3));
 243          $this->quba->finish_all_questions();
 244  
 245          // Verify.
 246          $this->check_current_state(question_state::$gradedright);
 247          $this->check_current_mark(3);
 248          $this->check_current_output(
 249                  $this->get_contains_mc_radio_expectation($rightindex, false, true),
 250                  $this->get_contains_cbm_radio_expectation(question_cbm::HIGH, false, true),
 251                  $this->get_contains_correct_expectation());
 252          $this->assertRegExp('/(A) \[' . preg_quote(question_cbm::get_short_string(question_cbm::HIGH), '/') . '\]/',
 253                  $this->quba->get_response_summary($this->slot));
 254      }
 255  
 256      public function test_deferred_cbm_truefalse_no_certainty_feedback_when_not_answered() {
 257  
 258          // Create a true-false question with correct answer true.
 259          $tf = test_question_maker::make_question('truefalse', 'true');
 260          $this->start_attempt_at_question($tf, 'deferredcbm', 2);
 261  
 262          // Verify.
 263          $this->check_current_state(question_state::$todo);
 264          $this->check_output_contains_lang_string('notyetanswered', 'question');
 265          $this->check_current_mark(null);
 266          $this->check_current_output(
 267                  $this->get_does_not_contain_correctness_expectation(),
 268                  $this->get_contains_cbm_radio_expectation(1, true, false),
 269                  $this->get_does_not_contain_feedback_expectation());
 270  
 271          // Finish without answering.
 272          $this->quba->finish_all_questions();
 273  
 274          // Verify.
 275          $this->check_current_state(question_state::$gaveup);
 276          $this->check_current_mark(null);
 277          $this->check_current_output(
 278                  new question_no_pattern_expectation('/class=\"im-feedback/'));
 279      }
 280  }