<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_question\local\statistics;
> defined('MOODLE_INTERNAL') || die();
use advanced_testcase;
>
use context;
use context_module;
use core_question\statistics\questions\all_calculated_for_qubaid_condition;
> use quiz_statistics\tests\statistics_helper;
use core_question_generator;
use Generator;
< use quiz;
< use quiz_attempt;
> use mod_quiz\quiz_attempt;
> use mod_quiz\quiz_settings;
use question_engine;
use ReflectionMethod;
> global $CFG;
/**
> require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
* Tests for question statistics.
>
*
* @package core_question
* @copyright 2021 Catalyst IT Australia Pty Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \core_question\local\statistics\statistics_bulk_loader
*/
class statistics_bulk_loader_test extends advanced_testcase {
> use \quiz_question_helper_test_trait;
/** @var float Delta used when comparing statistics values out-of 1. */
>
protected const DELTA = 0.00005;
/** @var float Delta used when comparing statistics values out-of 100. */
protected const PERCENT_DELTA = 0.005;
/**
* Test quizzes that contain a specified question.
*
* @covers ::get_all_places_where_questions_were_attempted
*/
public function test_get_all_places_where_questions_were_attempted(): void {
> global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$rcm = new ReflectionMethod(statistics_bulk_loader::class, 'get_all_places_where_questions_were_attempted');
$rcm->setAccessible(true);
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create three quizzes.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz1 = $quizgenerator->create_instance([
'course' => $course->id,
'grade' => 100.0, 'sumgrades' => 2,
'layout' => '1,2,0'
]);
$quiz1context = context_module::instance($quiz1->cmid);
$quiz2 = $quizgenerator->create_instance([
'course' => $course->id,
'grade' => 100.0, 'sumgrades' => 2,
'layout' => '1,2,0'
]);
$quiz2context = context_module::instance($quiz2->cmid);
$quiz3 = $quizgenerator->create_instance([
'course' => $course->id,
'grade' => 100.0, 'sumgrades' => 2,
'layout' => '1,2,0'
]);
$quiz3context = context_module::instance($quiz3->cmid);
// Create questions.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$question1 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
$question2 = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
// Add question 1 to quiz 1 and make an attempt.
quiz_add_quiz_question($question1->id, $quiz1);
// Quiz 1 attempt.
$this->submit_quiz($quiz1, [1 => ['answer' => 'frog']]);
// Add questions 1 and 2 to quiz 2.
quiz_add_quiz_question($question1->id, $quiz2);
quiz_add_quiz_question($question2->id, $quiz2);
$this->submit_quiz($quiz2, [1 => ['answer' => 'frog'], 2 => ['answer' => 10]]);
// Checking quizzes that use question 1.
$q1places = $rcm->invoke(null, [$question1->id]);
$this->assertCount(2, $q1places);
$this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz1context->id], $q1places[0]);
$this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz2context->id], $q1places[1]);
// Checking quizzes that contain question 2.
$q2places = $rcm->invoke(null, [$question2->id]);
$this->assertCount(1, $q2places);
$this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz2context->id], $q2places[0]);
// Add a random question to quiz3.
< quiz_add_random_questions($quiz3, 0, $cat->id, 1, false);
> $this->add_random_questions($quiz3->id, 0, $cat->id, 1, false);
$this->submit_quiz($quiz3, [1 => ['answer' => 'willbewrong']]);
// Quiz 3 will now be in one of these arrays.
$q1places = $rcm->invoke(null, [$question1->id]);
$q2places = $rcm->invoke(null, [$question2->id]);
if (count($q1places) == 3) {
$newplace = end($q1places);
} else {
$newplace = end($q2places);
}
$this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz3context->id], $newplace);
>
}
> // Simulate the situation where the context for quiz3 is gone from the database, without
> // the corresponding attempt data being properly cleaned up. Ensure this does not cause errors.
/**
> $DB->delete_records('context', ['id' => context_module::instance($quiz3->cmid)->id]);
* Create 2 quizzes.
> accesslib_clear_all_caches_for_unit_testing();
*
> // Same asserts as above, before we added quiz3.
* @return array return 2 quizzes
> $q1places = $rcm->invoke(null, [$question1->id]);
*/
> $this->assertCount(2, $q1places);
private function prepare_quizzes(): array {
> $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz1context->id], $q1places[0]);
// Create a course.
> $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz2context->id], $q1places[1]);
$course = $this->getDataGenerator()->create_course();
> $q2places = $rcm->invoke(null, [$question2->id]);
> $this->assertCount(1, $q2places);
// Make 2 quizzes.
> $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz2context->id], $q2places[0]);
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$layout = '1,2,0,3,4,0';
$quiz1 = $quizgenerator->create_instance([
'course' => $course->id,
'grade' => 100.0, 'sumgrades' => 2,
'layout' => $layout
]);
$quiz2 = $quizgenerator->create_instance([
'course' => $course->id,
'grade' => 100.0, 'sumgrades' => 2,
'layout' => $layout
]);
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$page = 1;
$questions = [];
foreach (explode(',', $layout) as $slot) {
if ($slot == 0) {
$page += 1;
continue;
}
$question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
$questions[$slot] = $question;
quiz_add_quiz_question($question->id, $quiz1, $page);
quiz_add_quiz_question($question->id, $quiz2, $page);
}
return [$quiz1, $quiz2, $questions];
}
/**
* Submit quiz answers
*
* @param object $quiz
* @param array $answers
*/
private function submit_quiz(object $quiz, array $answers): void {
// Create user.
$user = $this->getDataGenerator()->create_user();
// Create attempt.
< $quizobj = quiz::create($quiz->id, $user->id);
> $quizobj = quiz_settings::create($quiz->id, $user->id);
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
$timenow = time();
$attempt = quiz_create_attempt($quizobj, 1, null, $timenow, false, $user->id);
quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
quiz_attempt_save_started($quizobj, $quba, $attempt);
// Submit attempt.
$attemptobj = quiz_attempt::create($attempt->id);
$attemptobj->process_submitted_actions($timenow, false, $answers);
$attemptobj->process_finish($timenow, false);
}
/**
* Generate attempt answers.
*
* @param array $correctanswerflags array of 1 or 0
* 1 : generate correct answer
* 0 : generate wrong answer
*
* @return array
*/
private function generate_attempt_answers(array $correctanswerflags): array {
$attempt = [];
for ($i = 1; $i <= 4; $i++) {
if (isset($correctanswerflags) && $correctanswerflags[$i - 1] == 1) {
// Correct answer.
$attempt[$i] = ['answer' => 'frog'];
} else {
$attempt[$i] = ['answer' => 'false'];
}
}
return $attempt;
}
/**
* Generate quizzes and submit answers.
*
* @param array $quiz1attempts quiz 1 attempts
* @param array $quiz2attempts quiz 2 attempts
*
* @return array
*/
private function prepare_and_submit_quizzes(array $quiz1attempts, array $quiz2attempts): array {
list($quiz1, $quiz2, $questions) = $this->prepare_quizzes();
// Submit attempts of quiz1.
foreach ($quiz1attempts as $attempt) {
$this->submit_quiz($quiz1, $attempt);
}
// Submit attempts of quiz2.
foreach ($quiz2attempts as $attempt) {
$this->submit_quiz($quiz2, $attempt);
}
// Calculate the statistics.
$this->expectOutputRegex('~.*Calculations completed.*~');
< $statisticstask = new \quiz_statistics\task\recalculate();
< $statisticstask->execute();
> statistics_helper::run_pending_recalculation_tasks();
return [$quiz1, $quiz2, $questions];
}
/**
* To use private helper::extract_item_value function.
*
* @param all_calculated_for_qubaid_condition $statistics the batch of statistics.
* @param int $questionid a question id.
* @param string $item one of the field names in all_calculated_for_qubaid_condition, e.g. 'facility'.
* @return float|null the required value.
*/
private function extract_item_value(all_calculated_for_qubaid_condition $statistics,
int $questionid, string $item): ?float {
$rcm = new ReflectionMethod(statistics_bulk_loader::class, 'extract_item_value');
$rcm->setAccessible(true);
return $rcm->invoke(null, $statistics, $questionid, $item);
}
/**
* To use private helper::load_statistics_for_place function (with mod_quiz component).
*
* @param context $context the context to load the statistics for.
* @return all_calculated_for_qubaid_condition|null question statistics.
*/
private function load_quiz_statistics_for_place(context $context): ?all_calculated_for_qubaid_condition {
$rcm = new ReflectionMethod(statistics_bulk_loader::class, 'load_statistics_for_place');
$rcm->setAccessible(true);
return $rcm->invoke(null, 'mod_quiz', $context);
}
/**
* Data provider for {@see test_load_question_facility()}.
*
* @return Generator
*/
public function load_question_facility_provider(): Generator {
yield 'Facility case 1' => [
'Quiz 1 attempts' => [
$this->generate_attempt_answers([1, 0, 0, 0]),
],
'Expected quiz 1 facilities' => [1.0, 0.0, 0.0, 0.0],
'Quiz 2 attempts' => [
$this->generate_attempt_answers([1, 0, 0, 0]),
$this->generate_attempt_answers([1, 1, 0, 0]),
],
'Expected quiz 2 facilities' => [1.0, 0.5, 0.0, 0.0],
'Expected average facilities' => [1.0, 0.25, 0.0, 0.0],
];
yield 'Facility case 2' => [
'Quiz 1 attempts' => [
$this->generate_attempt_answers([1, 0, 0, 0]),
$this->generate_attempt_answers([1, 1, 0, 0]),
$this->generate_attempt_answers([1, 1, 1, 0]),
],
'Expected quiz 1 facilities' => [1.0, 0.6667, 0.3333, 0.0],
'Quiz 2 attempts' => [
$this->generate_attempt_answers([1, 0, 0, 0]),
$this->generate_attempt_answers([1, 1, 0, 0]),
$this->generate_attempt_answers([1, 1, 1, 0]),
$this->generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 2 facilities' => [1.0, 0.75, 0.5, 0.25],
'Expected average facilities' => [1.0, 0.7083, 0.4167, 0.1250],
];
}
/**
* Test question facility
*
* @dataProvider load_question_facility_provider
*
* @param array $quiz1attempts quiz 1 attempts
* @param array $expectedquiz1facilities expected quiz 1 facilities
* @param array $quiz2attempts quiz 2 attempts
* @param array $expectedquiz2facilities expected quiz 2 facilities
* @param array $expectedaveragefacilities expected average facilities
*/
public function test_load_question_facility(
array $quiz1attempts,
array $expectedquiz1facilities,
array $quiz2attempts,
array $expectedquiz2facilities,
array $expectedaveragefacilities)
: void {
$this->resetAfterTest();
list($quiz1, $quiz2, $questions) = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
// Quiz 1 facilities.
$stats = $this->load_quiz_statistics_for_place(context_module::instance($quiz1->cmid));
$quiz1facility1 = $this->extract_item_value($stats, $questions[1]->id, 'facility');
$quiz1facility2 = $this->extract_item_value($stats, $questions[2]->id, 'facility');
$quiz1facility3 = $this->extract_item_value($stats, $questions[3]->id, 'facility');
$quiz1facility4 = $this->extract_item_value($stats, $questions[4]->id, 'facility');
$this->assertEqualsWithDelta($expectedquiz1facilities[0], $quiz1facility1, self::DELTA);
$this->assertEqualsWithDelta($expectedquiz1facilities[1], $quiz1facility2, self::DELTA);
$this->assertEqualsWithDelta($expectedquiz1facilities[2], $quiz1facility3, self::DELTA);
$this->assertEqualsWithDelta($expectedquiz1facilities[3], $quiz1facility4, self::DELTA);
// Quiz 2 facilities.
$stats = $this->load_quiz_statistics_for_place(context_module::instance($quiz2->cmid));
$quiz2facility1 = $this->extract_item_value($stats, $questions[1]->id, 'facility');
$quiz2facility2 = $this->extract_item_value($stats, $questions[2]->id, 'facility');
$quiz2facility3 = $this->extract_item_value($stats, $questions[3]->id, 'facility');
$quiz2facility4 = $this->extract_item_value($stats, $questions[4]->id, 'facility');
$this->assertEqualsWithDelta($expectedquiz2facilities[0], $quiz2facility1, self::DELTA);
$this->assertEqualsWithDelta($expectedquiz2facilities[1], $quiz2facility2, self::DELTA);
$this->assertEqualsWithDelta($expectedquiz2facilities[2], $quiz2facility3, self::DELTA);
$this->assertEqualsWithDelta($expectedquiz2facilities[3], $quiz2facility4, self::DELTA);
// Average question facilities.
$stats = statistics_bulk_loader::load_aggregate_statistics(
[$questions[1]->id, $questions[2]->id, $questions[3]->id, $questions[4]->id],
['facility']
);
$this->assertEqualsWithDelta($expectedaveragefacilities[0],
$stats[$questions[1]->id]['facility'], self::DELTA);
$this->assertEqualsWithDelta($expectedaveragefacilities[1],
$stats[$questions[2]->id]['facility'], self::DELTA);
$this->assertEqualsWithDelta($expectedaveragefacilities[2],
$stats[$questions[3]->id]['facility'], self::DELTA);
$this->assertEqualsWithDelta($expectedaveragefacilities[3],
$stats[$questions[4]->id]['facility'], self::DELTA);
}
/**
* Data provider for {@see test_load_question_discriminative_efficiency()}.
* @return Generator
*/
public function load_question_discriminative_efficiency_provider(): Generator {
yield 'Discriminative efficiency' => [
'Quiz 1 attempts' => [
$this->generate_attempt_answers([1, 0, 0, 0]),
$this->generate_attempt_answers([1, 1, 0, 0]),
$this->generate_attempt_answers([1, 0, 1, 0]),
$this->generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 1 discriminative efficiency' => [null, 33.33, 33.33, 100.00],
'Quiz 2 attempts' => [
$this->generate_attempt_answers([1, 1, 1, 1]),
$this->generate_attempt_answers([0, 0, 0, 0]),
$this->generate_attempt_answers([1, 0, 0, 1]),
$this->generate_attempt_answers([0, 1, 1, 0]),
],
'Expected quiz 2 discriminative efficiency' => [50.00, 50.00, 50.00, 50.00],
'Expected average discriminative efficiency' => [50.00, 41.67, 41.67, 75.00],
];
}
/**
* Test discriminative efficiency
*
* @dataProvider load_question_discriminative_efficiency_provider
*
* @param array $quiz1attempts quiz 1 attempts
* @param array $expectedquiz1discriminativeefficiency expected quiz 1 discriminative efficiency
* @param array $quiz2attempts quiz 2 attempts
* @param array $expectedquiz2discriminativeefficiency expected quiz 2 discriminative efficiency
* @param array $expectedaveragediscriminativeefficiency expected average discriminative efficiency
*/
public function test_load_question_discriminative_efficiency(
array $quiz1attempts,
array $expectedquiz1discriminativeefficiency,
array $quiz2attempts,
array $expectedquiz2discriminativeefficiency,
array $expectedaveragediscriminativeefficiency
): void {
$this->resetAfterTest();
list($quiz1, $quiz2, $questions) = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
// Quiz 1 discriminative efficiency.
$stats = $this->load_quiz_statistics_for_place(context_module::instance($quiz1->cmid));
$discriminativeefficiency1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminativeefficiency');
$discriminativeefficiency2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminativeefficiency');
$discriminativeefficiency3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminativeefficiency');
$discriminativeefficiency4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminativeefficiency');
$this->assertEqualsWithDelta($expectedquiz1discriminativeefficiency[0],
$discriminativeefficiency1, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz1discriminativeefficiency[1],
$discriminativeefficiency2, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz1discriminativeefficiency[2],
$discriminativeefficiency3, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz1discriminativeefficiency[3],
$discriminativeefficiency4, self::PERCENT_DELTA);
// Quiz 2 discriminative efficiency.
$stats = $this->load_quiz_statistics_for_place(context_module::instance($quiz2->cmid));
$discriminativeefficiency1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminativeefficiency');
$discriminativeefficiency2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminativeefficiency');
$discriminativeefficiency3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminativeefficiency');
$discriminativeefficiency4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminativeefficiency');
$this->assertEqualsWithDelta($expectedquiz2discriminativeefficiency[0],
$discriminativeefficiency1, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz2discriminativeefficiency[1],
$discriminativeefficiency2, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz2discriminativeefficiency[2],
$discriminativeefficiency3, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz2discriminativeefficiency[3],
$discriminativeefficiency4, self::PERCENT_DELTA);
// Average question discriminative efficiency.
$stats = statistics_bulk_loader::load_aggregate_statistics(
[$questions[1]->id, $questions[2]->id, $questions[3]->id, $questions[4]->id],
['discriminativeefficiency']
);
$this->assertEqualsWithDelta($expectedaveragediscriminativeefficiency[0],
$stats[$questions[1]->id]['discriminativeefficiency'], self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedaveragediscriminativeefficiency[1],
$stats[$questions[2]->id]['discriminativeefficiency'], self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedaveragediscriminativeefficiency[2],
$stats[$questions[3]->id]['discriminativeefficiency'], self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedaveragediscriminativeefficiency[3],
$stats[$questions[4]->id]['discriminativeefficiency'], self::PERCENT_DELTA);
}
/**
* Data provider for {@see test_load_question_discrimination_index()}.
* @return Generator
*/
public function load_question_discrimination_index_provider(): Generator {
yield 'Discrimination Index' => [
'Quiz 1 attempts' => [
$this->generate_attempt_answers([1, 0, 0, 0]),
$this->generate_attempt_answers([1, 1, 0, 0]),
$this->generate_attempt_answers([1, 0, 1, 0]),
$this->generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 1 Discrimination Index' => [null, 30.15, 30.15, 81.65],
'Quiz 2 attempts' => [
$this->generate_attempt_answers([1, 1, 1, 1]),
$this->generate_attempt_answers([0, 0, 0, 0]),
$this->generate_attempt_answers([1, 0, 0, 1]),
$this->generate_attempt_answers([0, 1, 1, 0]),
],
'Expected quiz 2 discrimination Index' => [44.72, 44.72, 44.72, 44.72],
'Expected average discrimination Index' => [44.72, 37.44, 37.44, 63.19],
];
}
/**
* Test discrimination index
*
* @dataProvider load_question_discrimination_index_provider
*
* @param array $quiz1attempts quiz 1 attempts
* @param array $expectedquiz1discriminationindex expected quiz 1 discrimination index
* @param array $quiz2attempts quiz 2 attempts
* @param array $expectedquiz2discriminationindex expected quiz 2 discrimination index
* @param array $expectedaveragediscriminationindex expected average discrimination index
*/
public function test_load_question_discrimination_index(
array $quiz1attempts,
array $expectedquiz1discriminationindex,
array $quiz2attempts,
array $expectedquiz2discriminationindex,
array $expectedaveragediscriminationindex
): void {
$this->resetAfterTest();
list($quiz1, $quiz2, $questions) = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
// Quiz 1 discrimination index.
$stats = $this->load_quiz_statistics_for_place(context_module::instance($quiz1->cmid));
$discriminationindex1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminationindex');
$discriminationindex2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminationindex');
$discriminationindex3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminationindex');
$discriminationindex4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminationindex');
$this->assertEqualsWithDelta($expectedquiz1discriminationindex[0],
$discriminationindex1, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz1discriminationindex[1],
$discriminationindex2, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz1discriminationindex[2],
$discriminationindex3, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz1discriminationindex[3],
$discriminationindex4, self::PERCENT_DELTA);
// Quiz 2 discrimination index.
$stats = $this->load_quiz_statistics_for_place(context_module::instance($quiz2->cmid));
$discriminationindex1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminationindex');
$discriminationindex2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminationindex');
$discriminationindex3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminationindex');
$discriminationindex4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminationindex');
$this->assertEqualsWithDelta($expectedquiz2discriminationindex[0],
$discriminationindex1, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz2discriminationindex[1],
$discriminationindex2, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz2discriminationindex[2],
$discriminationindex3, self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedquiz2discriminationindex[3],
$discriminationindex4, self::PERCENT_DELTA);
// Average question discrimination index.
$stats = statistics_bulk_loader::load_aggregate_statistics(
[$questions[1]->id, $questions[2]->id, $questions[3]->id, $questions[4]->id],
['discriminationindex']
);
$this->assertEqualsWithDelta($expectedaveragediscriminationindex[0],
$stats[$questions[1]->id]['discriminationindex'], self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedaveragediscriminationindex[1],
$stats[$questions[2]->id]['discriminationindex'], self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedaveragediscriminationindex[2],
$stats[$questions[3]->id]['discriminationindex'], self::PERCENT_DELTA);
$this->assertEqualsWithDelta($expectedaveragediscriminationindex[3],
$stats[$questions[4]->id]['discriminationindex'], self::PERCENT_DELTA);
}
/**
* Test with question statistics disabled
*/
public function test_statistics_disabled(): void {
$this->resetAfterTest();
// Prepare some quizzes and attempts. Exactly what is not important to this test.
$quiz1attempts = [$this->generate_attempt_answers([1, 0, 0, 0])];
$quiz2attempts = [$this->generate_attempt_answers([1, 1, 1, 1])];
[, , $questions] = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
// Prepare some useful arrays.
$expectedstats = [
$questions[1]->id => [],
$questions[2]->id => [],
$questions[3]->id => [],
$questions[4]->id => [],
];
$questionids = array_keys($expectedstats);
// Ask to load no statistics at all.
$stats = statistics_bulk_loader::load_aggregate_statistics($questionids, []);
// Verify we got the right thing.
$this->assertEquals($expectedstats, $stats);
}
}