Ejemplo n.º 1
0
 public function test_immediatecbm_feedback_multichoice_right()
 {
     // Create a true-false question with correct answer true.
     $mc = test_question_maker::make_a_multichoice_single_question();
     $this->start_attempt_at_question($mc, 'immediatecbm');
     $rightindex = $this->get_mc_right_answer_index($mc);
     $wrongindex = ($rightindex + 1) % 3;
     // Check the initial state.
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->check_current_output($this->get_contains_question_text_expectation($mc), $this->get_contains_mc_radio_expectation(0, true, false), $this->get_contains_mc_radio_expectation(1, true, false), $this->get_contains_mc_radio_expectation(2, true, false), $this->get_contains_submit_button_expectation(true), $this->get_does_not_contain_feedback_expectation());
     $this->assertEquals('A [' . question_cbm::get_short_string(question_cbm::HIGH) . ']', $this->quba->get_right_answer_summary($this->slot));
     $this->assertRegExp('/' . preg_quote($mc->questiontext, '/') . '/', $this->quba->get_question_summary($this->slot));
     $this->assertNull($this->quba->get_response_summary($this->slot));
     // Save the wrong answer.
     $this->process_submission(array('answer' => $wrongindex, '-certainty' => 1));
     // Verify.
     $this->check_current_state(question_state::$todo);
     $this->check_current_mark(null);
     $this->check_current_output($this->get_contains_mc_radio_expectation($wrongindex, true, true), $this->get_contains_mc_radio_expectation(($wrongindex + 1) % 3, true, false), $this->get_contains_mc_radio_expectation(($wrongindex + 1) % 3, true, false), $this->get_contains_submit_button_expectation(true), $this->get_does_not_contain_correctness_expectation(), $this->get_does_not_contain_feedback_expectation());
     // Submit the right answer.
     $this->process_submission(array('answer' => $rightindex, '-certainty' => 2, '-submit' => 1));
     // Verify.
     $this->check_current_state(question_state::$gradedright);
     $this->check_current_mark(2);
     $this->check_current_output($this->get_contains_mc_radio_expectation($rightindex, false, true), $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false), $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false), $this->get_contains_correct_expectation());
     $this->assertEquals('A [' . question_cbm::get_short_string(2) . ']', $this->quba->get_response_summary($this->slot));
     $numsteps = $this->get_step_count();
     // Finish the attempt - should not need to add a new state.
     $this->quba->finish_all_questions();
     // Verify.
     $this->assertEquals($numsteps, $this->get_step_count());
     $this->check_current_state(question_state::$gradedright);
     $this->check_current_mark(2);
     $this->check_current_output($this->get_contains_mc_radio_expectation($rightindex, false, true), $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false), $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false), $this->get_contains_correct_expectation());
     // Process a manual comment.
     $this->manual_grade('Not good enough!', 0.5, FORMAT_HTML);
     // Verify.
     $this->check_current_state(question_state::$mangrpartial);
     $this->check_current_mark(0.5);
     $this->check_current_output($this->get_contains_partcorrect_expectation(), new question_pattern_expectation('/' . preg_quote('Not good enough!', '/') . '/'));
     // Now change the correct answer to the question, and regrade.
     $mc->answers[13]->fraction = -0.33333333;
     $mc->answers[15]->fraction = 1;
     $this->quba->regrade_all_questions();
     // Verify.
     $this->check_current_state(question_state::$mangrpartial);
     $this->check_current_mark(0.5);
     $this->check_current_output($this->get_contains_partcorrect_expectation());
     $autogradedstep = $this->get_step($this->get_step_count() - 2);
     $this->assertEquals($autogradedstep->get_fraction(), -2, '', 1.0E-7);
 }
 public function summarise_usage(question_usage_by_activity $quba, question_display_options $options)
 {
     $summarydata = parent::summarise_usage($quba, $options);
     if ($options->marks < question_display_options::MARK_AND_MAX) {
         return $summarydata;
     }
     // Prepare accumulators to hold the data we are about to collect.
     $notansweredcount = 0;
     $notansweredweight = 0;
     $attemptcount = array(question_cbm::HIGH => 0, question_cbm::MED => 0, question_cbm::LOW => 0);
     $totalweight = array(question_cbm::HIGH => 0, question_cbm::MED => 0, question_cbm::LOW => 0);
     $totalrawscore = array(question_cbm::HIGH => 0, question_cbm::MED => 0, question_cbm::LOW => 0);
     $totalcbmscore = array(question_cbm::HIGH => 0, question_cbm::MED => 0, question_cbm::LOW => 0);
     // Loop through the data, and add it to the accumulators.
     foreach ($quba->get_attempt_iterator() as $qa) {
         if (strpos($qa->get_behaviour_name(), 'cbm') === false || $qa->get_max_mark() < 5.0E-7) {
             continue;
         }
         $gradedstep = $qa->get_last_step_with_behaviour_var('_rawfraction');
         if (!$gradedstep->has_behaviour_var('_rawfraction')) {
             $notansweredcount += 1;
             $notansweredweight += $qa->get_max_mark();
             continue;
         }
         $certainty = $qa->get_last_behaviour_var('certainty');
         if (is_null($certainty) || $certainty == -1) {
             // Certainty -1 has never been used in standard Moodle, but is
             // used in Tony-Gardiner Medwin's patches to mean 'No idea' which
             // we intend to implement: MDL-42077. In the mean time, avoid
             // errors for people who have used TGM's patches.
             $certainty = question_cbm::default_certainty();
         }
         $attemptcount[$certainty] += 1;
         $totalweight[$certainty] += $qa->get_max_mark();
         $totalrawscore[$certainty] += $qa->get_max_mark() * $gradedstep->get_behaviour_var('_rawfraction');
         $totalcbmscore[$certainty] += $qa->get_mark();
     }
     // Hence compute some statistics.
     $totalquestions = $notansweredcount + array_sum($attemptcount);
     $grandtotalweight = $notansweredweight + array_sum($totalweight);
     $accuracy = array_sum($totalrawscore) / $grandtotalweight;
     $averagecbm = array_sum($totalcbmscore) / $grandtotalweight;
     $cbmbonus = $this->calculate_bonus($averagecbm, $accuracy);
     $accuracyandbonus = $accuracy + $cbmbonus;
     // Now we can start generating some of the summary: overall values.
     $summarydata['qbehaviour_cbm_entire_quiz_heading'] = array('title' => '', 'content' => html_writer::tag('h3', get_string('forentirequiz', 'qbehaviour_deferredcbm', $totalquestions), array('class' => 'qbehaviour_deferredcbm_summary_heading')));
     $summarydata['qbehaviour_cbm_entire_quiz_cbm_average'] = array('title' => get_string('averagecbmmark', 'qbehaviour_deferredcbm'), 'content' => format_float($averagecbm, $options->markdp));
     $summarydata['qbehaviour_cbm_entire_quiz_accuracy'] = array('title' => get_string('accuracy', 'qbehaviour_deferredcbm'), 'content' => $this->format_probability($accuracy, 1));
     $summarydata['qbehaviour_cbm_entire_quiz_cbm_bonus'] = array('title' => get_string('cbmbonus', 'qbehaviour_deferredcbm'), 'content' => $this->format_probability($cbmbonus, 1));
     $summarydata['qbehaviour_cbm_entire_quiz_accuracy_and_bonus'] = array('title' => get_string('accuracyandbonus', 'qbehaviour_deferredcbm'), 'content' => $this->format_probability($accuracyandbonus, 1));
     if ($notansweredcount && array_sum($attemptcount) > 0) {
         $totalquestions = array_sum($attemptcount);
         $grandtotalweight = array_sum($totalweight);
         $accuracy = array_sum($totalrawscore) / $grandtotalweight;
         $averagecbm = array_sum($totalcbmscore) / $grandtotalweight;
         $cbmbonus = $this->calculate_bonus($averagecbm, $accuracy);
         $accuracyandbonus = $accuracy + $cbmbonus;
         $summarydata['qbehaviour_cbm_answered_quiz_heading'] = array('title' => '', 'content' => html_writer::tag('h3', get_string('foransweredquestions', 'qbehaviour_deferredcbm', $totalquestions), array('class' => 'qbehaviour_deferredcbm_summary_heading')));
         $summarydata['qbehaviour_cbm_answered_quiz_cbm_average'] = array('title' => get_string('averagecbmmark', 'qbehaviour_deferredcbm'), 'content' => format_float($averagecbm, $options->markdp));
         $summarydata['qbehaviour_cbm_answered_quiz_accuracy'] = array('title' => get_string('accuracy', 'qbehaviour_deferredcbm'), 'content' => $this->format_probability($accuracy, 1));
         $summarydata['qbehaviour_cbm_answered_quiz_cbm_bonus'] = array('title' => get_string('cbmbonus', 'qbehaviour_deferredcbm'), 'content' => $this->format_probability($cbmbonus, 1));
         $summarydata['qbehaviour_cbm_answered_quiz_accuracy_and_bonus'] = array('title' => get_string('accuracyandbonus', 'qbehaviour_deferredcbm'), 'content' => $this->format_probability($accuracyandbonus, 1));
     }
     // Now per-certainty level values.
     $summarydata['qbehaviour_cbm_judgement_heading'] = array('title' => '', 'content' => html_writer::tag('h3', get_string('breakdownbycertainty', 'qbehaviour_deferredcbm'), array('class' => 'qbehaviour_deferredcbm_summary_heading')));
     foreach ($attemptcount as $certainty => $count) {
         $key = 'qbehaviour_cbm_judgement' . $certainty;
         $title = question_cbm::get_short_string($certainty);
         if ($count == 0) {
             $summarydata[$key] = array('title' => $title, 'content' => get_string('noquestions', 'qbehaviour_deferredcbm'));
             continue;
         }
         $lowerlimit = question_cbm::optimal_probablility_low($certainty);
         $upperlimit = question_cbm::optimal_probablility_high($certainty);
         $fraction = $totalrawscore[$certainty] / $totalweight[$certainty];
         $a = new stdClass();
         $a->responses = $count;
         $a->idealrangelow = $this->format_probability($lowerlimit);
         $a->idealrangehigh = $this->format_probability($upperlimit);
         $a->fraction = html_writer::tag('span', $this->format_probability($fraction), array('class' => 'qbehaviour_deferredcbm_actual_percentage'));
         if ($fraction < $lowerlimit - 5.0E-7) {
             if (pow($fraction - $lowerlimit, 2) * $count > 0.5) {
                 // Rough indicator of significance: t > 1.5 or 1.8.
                 $judgement = 'overconfident';
             } else {
                 $judgement = 'slightlyoverconfident';
             }
         } else {
             if ($fraction > $upperlimit + 5.0E-7) {
                 if (pow($fraction - $upperlimit, 2) * $count > 0.5) {
                     $judgement = 'underconfident';
                 } else {
                     $judgement = 'slightlyunderconfident';
                 }
             } else {
                 $judgement = 'judgementok';
             }
         }
         $a->judgement = html_writer::tag('span', get_string($judgement, 'qbehaviour_deferredcbm'), array('class' => 'qbehaviour_deferredcbm_' . $judgement));
         $summarydata[$key] = array('title' => $title, 'content' => get_string('judgementsummary', 'qbehaviour_deferredcbm', $a));
     }
     return $summarydata;
 }
Ejemplo n.º 3
0
 public function test_deferredcbm_resume_multichoice_single()
 {
     // Create a multiple-choice question.
     $mc = test_question_maker::make_a_multichoice_single_question();
     // Attempt it getting it wrong.
     $this->start_attempt_at_question($mc, 'deferredcbm', 1);
     $rightindex = $this->get_mc_right_answer_index($mc);
     $wrongindex = ($rightindex + 1) % 3;
     $this->process_submission(array('answer' => $wrongindex, '-certainty' => 2));
     $this->quba->finish_all_questions();
     // Verify.
     $this->check_current_state(question_state::$gradedwrong);
     $this->check_current_mark(-2);
     $this->check_current_output($this->get_contains_mc_radio_expectation($wrongindex, false, true), $this->get_contains_cbm_radio_expectation(2, false, true), $this->get_contains_incorrect_expectation());
     $this->assertEquals('A [' . question_cbm::get_short_string(question_cbm::HIGH) . ']', $this->quba->get_right_answer_summary($this->slot));
     $this->assertRegExp('/' . preg_quote($mc->questiontext, '/') . '/', $this->quba->get_question_summary($this->slot));
     $this->assertRegExp('/(B|C) \\[' . preg_quote(question_cbm::get_short_string(question_cbm::MED), '/') . '\\]/', $this->quba->get_response_summary($this->slot));
     // Save the old attempt.
     $oldqa = $this->quba->get_question_attempt($this->slot);
     // Reinitialise.
     $this->setUp();
     $this->quba->set_preferred_behaviour('deferredcbm');
     $this->slot = $this->quba->add_question($mc, 1);
     $this->quba->start_question_based_on($this->slot, $oldqa);
     // Verify.
     $this->check_current_state(question_state::$complete);
     $this->check_output_contains_lang_string('notchanged', 'question');
     $this->check_current_mark(null);
     $this->check_current_output($this->get_contains_mc_radio_expectation($wrongindex, true, true), $this->get_contains_cbm_radio_expectation(2, true, true), $this->get_does_not_contain_feedback_expectation(), $this->get_does_not_contain_correctness_expectation());
     $this->assertEquals('A [' . question_cbm::get_short_string(question_cbm::HIGH) . ']', $this->quba->get_right_answer_summary($this->slot));
     $this->assertRegExp('/' . preg_quote($mc->questiontext, '/') . '/', $this->quba->get_question_summary($this->slot));
     $this->assertNull($this->quba->get_response_summary($this->slot));
     // Now get it right.
     $this->process_submission(array('answer' => $rightindex, '-certainty' => 3));
     $this->quba->finish_all_questions();
     // Verify.
     $this->check_current_state(question_state::$gradedright);
     $this->check_current_mark(3);
     $this->check_current_output($this->get_contains_mc_radio_expectation($rightindex, false, true), $this->get_contains_cbm_radio_expectation(question_cbm::HIGH, false, true), $this->get_contains_correct_expectation());
     $this->assertRegExp('/(A) \\[' . preg_quote(question_cbm::get_short_string(question_cbm::HIGH), '/') . '\\]/', $this->quba->get_response_summary($this->slot));
 }