Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
namespace qbank_statistics;
18
 
19
defined('MOODLE_INTERNAL') || die();
20
 
21
use core_question\statistics\questions\all_calculated_for_qubaid_condition;
22
use quiz_statistics\tests\statistics_helper;
23
use mod_quiz\quiz_attempt;
24
use mod_quiz\quiz_settings;
25
use question_engine;
26
 
27
global $CFG;
28
require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
29
 
30
/**
31
 * Tests for question statistics.
32
 *
33
 * @package    qbank_statistics
34
 * @copyright  2021 Catalyst IT Australia Pty Ltd
35
 * @author     Nathan Nguyen <nathannguyen@catalyst-au.net>
36
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 */
38
class helper_test extends \advanced_testcase {
39
 
40
    use \quiz_question_helper_test_trait;
41
 
42
    /**
43
     * Test quizzes that contain a specified question.
44
     *
45
     * @covers ::get_all_places_where_questions_were_attempted
46
     * @deprecated since Moodle 4.3 please use the method from statistics_bulk_loader.
47
     * @todo MDL-78090 Final deprecation in Moodle 4.7
48
     */
49
    public function test_get_all_places_where_questions_were_attempted(): void {
50
        $this->resetAfterTest();
51
        $this->setAdminUser();
52
 
53
        $rcm = new \ReflectionMethod(helper::class, 'get_all_places_where_questions_were_attempted');
54
 
55
        // Create a course.
56
        $course = $this->getDataGenerator()->create_course();
57
 
58
        // Create three quizzes.
59
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
60
        $quiz1 = $quizgenerator->create_instance([
61
            'course' => $course->id,
62
            'grade' => 100.0, 'sumgrades' => 2,
63
            'layout' => '1,2,0'
64
        ]);
65
        $quiz1context = \context_module::instance($quiz1->cmid);
66
 
67
        $quiz2 = $quizgenerator->create_instance([
68
            'course' => $course->id,
69
            'grade' => 100.0, 'sumgrades' => 2,
70
            'layout' => '1,2,0'
71
        ]);
72
        $quiz2context = \context_module::instance($quiz2->cmid);
73
 
74
        $quiz3 = $quizgenerator->create_instance([
75
            'course' => $course->id,
76
            'grade' => 100.0, 'sumgrades' => 2,
77
            'layout' => '1,2,0'
78
        ]);
79
        $quiz3context = \context_module::instance($quiz3->cmid);
80
 
81
        // Create questions.
82
        /** @var \core_question_generator $questiongenerator */
83
        $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
84
        $cat = $questiongenerator->create_question_category();
85
        $question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
86
        $question2 = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
87
 
88
        // Add question 1 to quiz 1 and make an attempt.
89
        quiz_add_quiz_question($question1->id, $quiz1);
90
        // Quiz 1 attempt.
91
        $this->submit_quiz($quiz1, [1 => ['answer' => 'frog']]);
92
 
93
        // Add questions 1 and 2 to quiz 2.
94
        quiz_add_quiz_question($question1->id, $quiz2);
95
        quiz_add_quiz_question($question2->id, $quiz2);
96
        $this->submit_quiz($quiz2, [1 => ['answer' => 'frog'], 2 => ['answer' => 10]]);
97
 
98
        // Checking quizzes that use question 1.
99
        $q1places = $rcm->invoke(null, [$question1->id]);
100
        $this->assertCount(2, $q1places);
101
        $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz1context->id], $q1places[0]);
102
        $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz2context->id], $q1places[1]);
103
 
104
        // Checking quizzes that contain question 2.
105
        $q2places = $rcm->invoke(null, [$question2->id]);
106
        $this->assertCount(1, $q2places);
107
        $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz2context->id], $q2places[0]);
108
 
109
        // Add a random question to quiz3.
110
        $this->add_random_questions($quiz3->id, 0, $cat->id, 1);
111
        $this->submit_quiz($quiz3, [1 => ['answer' => 'willbewrong']]);
112
 
113
        // Quiz 3 will now be in one of these arrays.
114
        $q1places = $rcm->invoke(null, [$question1->id]);
115
        $q2places = $rcm->invoke(null, [$question2->id]);
116
        if (count($q1places) == 3) {
117
            $newplace = end($q1places);
118
        } else {
119
            $newplace = end($q2places);
120
        }
121
        $this->assertEquals((object) ['component' => 'mod_quiz', 'contextid' => $quiz3context->id], $newplace);
122
    }
123
 
124
    /**
125
     * Create 2 quizzes.
126
     *
127
     * @return array return 2 quizzes
128
     * @throws \coding_exception
129
     */
130
    private function prepare_quizzes(): array {
131
        // Create a course.
132
        $course = $this->getDataGenerator()->create_course();
133
 
134
        // Make 2 quizzes.
135
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
136
        $layout = '1,2,0,3,4,0';
137
        $quiz1 = $quizgenerator->create_instance([
138
            'course' => $course->id,
139
            'grade' => 100.0, 'sumgrades' => 2,
140
            'layout' => $layout
141
        ]);
142
 
143
        $quiz2 = $quizgenerator->create_instance([
144
            'course' => $course->id,
145
            'grade' => 100.0, 'sumgrades' => 2,
146
            'layout' => $layout
147
        ]);
148
 
149
        /** @var \core_question_generator $questiongenerator */
150
        $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
151
        $cat = $questiongenerator->create_question_category();
152
 
153
        $page = 1;
154
        $questions = [];
155
        foreach (explode(',', $layout) as $slot) {
156
            if ($slot == 0) {
157
                $page += 1;
158
                continue;
159
            }
160
 
161
            $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
162
            $questions[$slot] = $question;
163
            quiz_add_quiz_question($question->id, $quiz1, $page);
164
            quiz_add_quiz_question($question->id, $quiz2, $page);
165
        }
166
 
167
        return [$quiz1, $quiz2, $questions];
168
    }
169
 
170
    /**
171
     * Submit quiz answers
172
     *
173
     * @param object $quiz
174
     * @param array $answers
175
     * @throws \moodle_exception
176
     */
177
    private function submit_quiz(object $quiz, array $answers): void {
178
        // Create user.
179
        $user = $this->getDataGenerator()->create_user();
180
        // Create attempt.
181
        $quizobj = quiz_settings::create($quiz->id, $user->id);
182
        $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
183
        $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
184
        $timenow = time();
185
        $attempt = quiz_create_attempt($quizobj, 1, null, $timenow, false, $user->id);
186
        quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
187
        quiz_attempt_save_started($quizobj, $quba, $attempt);
188
        // Submit attempt.
189
        $attemptobj = quiz_attempt::create($attempt->id);
190
        $attemptobj->process_submitted_actions($timenow, false, $answers);
191
        $attemptobj->process_finish($timenow, false);
192
    }
193
 
194
    /**
195
     * Generate attempt answers.
196
     *
197
     * @param array $correctanswerflags array of 1 or 0
198
     * 1 : generate correct answer
199
     * 0 : generate wrong answer
200
     *
201
     * @return array
202
     */
203
    private function generate_attempt_answers(array $correctanswerflags): array {
204
        $attempt = [];
205
        for ($i = 1; $i <= 4; $i++) {
206
            if (isset($correctanswerflags) && $correctanswerflags[$i - 1] == 1) {
207
                // Correct answer.
208
                $attempt[$i] = ['answer' => 'frog'];
209
            } else {
210
                $attempt[$i] = ['answer' => 'false'];
211
            }
212
        }
213
        return $attempt;
214
    }
215
 
216
    /**
217
     *
218
     * Generate quizzes and submit answers.
219
     *
220
     * @param array $quiz1attempts quiz 1 attempts
221
     * @param array $quiz2attempts quiz 2 attempts
222
     *
223
     * @return array
224
     */
225
    private function prepare_and_submit_quizzes(array $quiz1attempts, array $quiz2attempts): array {
226
        list($quiz1, $quiz2, $questions) = $this->prepare_quizzes();
227
        // Submit attempts of quiz1.
228
        foreach ($quiz1attempts as $attempt) {
229
            $this->submit_quiz($quiz1, $attempt);
230
        }
231
        // Submit attempts of quiz2.
232
        foreach ($quiz2attempts as $attempt) {
233
            $this->submit_quiz($quiz2, $attempt);
234
        }
235
 
236
        // Calculate the statistics.
237
        $this->expectOutputRegex('~.*Calculations completed.*~');
238
        statistics_helper::run_pending_recalculation_tasks();
239
 
240
        return [$quiz1, $quiz2, $questions];
241
    }
242
 
243
    /**
244
     * To use private helper::extract_item_value function.
245
     *
246
     * @param all_calculated_for_qubaid_condition $statistics the batch of statistics.
247
     * @param int $questionid a question id.
248
     * @param string $item one of the field names in all_calculated_for_qubaid_condition, e.g. 'facility'.
249
     * @return float|null the required value.
250
     */
251
    private function extract_item_value(all_calculated_for_qubaid_condition $statistics,
252
                                        int $questionid, string $item): ?float {
253
        $rcm = new \ReflectionMethod(helper::class, 'extract_item_value');
254
        return $rcm->invoke(null, $statistics, $questionid, $item);
255
    }
256
 
257
    /**
258
     * To use private helper::load_statistics_for_place function (with mod_quiz component).
259
     *
260
     * @param \context $context the context to load the statistics for.
261
     * @return all_calculated_for_qubaid_condition|null question statistics.
262
     */
263
    private function load_quiz_statistics_for_place(\context $context): ?all_calculated_for_qubaid_condition {
264
        $rcm = new \ReflectionMethod(helper::class, 'load_statistics_for_place');
265
        return $rcm->invoke(null, 'mod_quiz', $context);
266
    }
267
 
268
    /**
269
     * Data provider for {@see test_load_question_facility()}.
270
     *
271
     * @return \Generator
272
     */
273
    public function load_question_facility_provider(): \Generator {
274
        yield 'Facility case 1' => [
275
            'Quiz 1 attempts' => [
276
                $this->generate_attempt_answers([1, 0, 0, 0]),
277
            ],
278
            'Expected quiz 1 facilities' => ['100.00%', '0.00%', '0.00%', '0.00%'],
279
            'Quiz 2 attempts' => [
280
                $this->generate_attempt_answers([1, 0, 0, 0]),
281
                $this->generate_attempt_answers([1, 1, 0, 0]),
282
            ],
283
            'Expected quiz 2 facilities' => ['100.00%', '50.00%', '0.00%', '0.00%'],
284
            'Expected average facilities' => ['100.00%', '25.00%', '0.00%', '0.00%'],
285
        ];
286
        yield 'Facility case 2' => [
287
            'Quiz 1 attempts' => [
288
                $this->generate_attempt_answers([1, 0, 0, 0]),
289
                $this->generate_attempt_answers([1, 1, 0, 0]),
290
                $this->generate_attempt_answers([1, 1, 1, 0]),
291
            ],
292
            'Expected quiz 1 facilities' => ['100.00%', '66.67%', '33.33%', '0.00%'],
293
            'Quiz 2 attempts' => [
294
                $this->generate_attempt_answers([1, 0, 0, 0]),
295
                $this->generate_attempt_answers([1, 1, 0, 0]),
296
                $this->generate_attempt_answers([1, 1, 1, 0]),
297
                $this->generate_attempt_answers([1, 1, 1, 1]),
298
            ],
299
            'Expected quiz 2 facilities' => ['100.00%', '75.00%', '50.00%', '25.00%'],
300
            'Expected average facilities' => ['100.00%', '70.83%', '41.67%', '12.50%'],
301
        ];
302
    }
303
 
304
    /**
305
     * Test question facility
306
     *
307
     * @dataProvider load_question_facility_provider
308
     *
309
     * @param array $quiz1attempts quiz 1 attempts
310
     * @param array $expectedquiz1facilities expected quiz 1 facilities
311
     * @param array $quiz2attempts quiz 2 attempts
312
     * @param array $expectedquiz2facilities  expected quiz 2 facilities
313
     * @param array $expectedaveragefacilities expected average facilities
314
     * @deprecated since Moodle 4.3 please use the method from statistics_bulk_loader.
315
     * @todo MDL-78090 Final deprecation in Moodle 4.7
316
     */
317
    public function test_load_question_facility(
318
        array $quiz1attempts,
319
        array $expectedquiz1facilities,
320
        array $quiz2attempts,
321
        array $expectedquiz2facilities,
322
        array $expectedaveragefacilities
323
    ): void {
324
        $this->resetAfterTest();
325
 
326
        list($quiz1, $quiz2, $questions) = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
327
 
328
        // Quiz 1 facilities.
329
        $stats = $this->load_quiz_statistics_for_place(\context_module::instance($quiz1->cmid));
330
        $quiz1facility1 = $this->extract_item_value($stats, $questions[1]->id, 'facility');
331
        $quiz1facility2 = $this->extract_item_value($stats, $questions[2]->id, 'facility');
332
        $quiz1facility3 = $this->extract_item_value($stats, $questions[3]->id, 'facility');
333
        $quiz1facility4 = $this->extract_item_value($stats, $questions[4]->id, 'facility');
334
 
335
        $this->assertEquals($expectedquiz1facilities[0], helper::format_percentage($quiz1facility1));
336
        $this->assertEquals($expectedquiz1facilities[1], helper::format_percentage($quiz1facility2));
337
        $this->assertEquals($expectedquiz1facilities[2], helper::format_percentage($quiz1facility3));
338
        $this->assertEquals($expectedquiz1facilities[3], helper::format_percentage($quiz1facility4));
339
 
340
        // Quiz 2 facilities.
341
        $stats = $this->load_quiz_statistics_for_place(\context_module::instance($quiz2->cmid));
342
        $quiz2facility1 = $this->extract_item_value($stats, $questions[1]->id, 'facility');
343
        $quiz2facility2 = $this->extract_item_value($stats, $questions[2]->id, 'facility');
344
        $quiz2facility3 = $this->extract_item_value($stats, $questions[3]->id, 'facility');
345
        $quiz2facility4 = $this->extract_item_value($stats, $questions[4]->id, 'facility');
346
 
347
        $this->assertEquals($expectedquiz2facilities[0], helper::format_percentage($quiz2facility1));
348
        $this->assertEquals($expectedquiz2facilities[1], helper::format_percentage($quiz2facility2));
349
        $this->assertEquals($expectedquiz2facilities[2], helper::format_percentage($quiz2facility3));
350
        $this->assertEquals($expectedquiz2facilities[3], helper::format_percentage($quiz2facility4));
351
 
352
        // Average question facilities.
353
        $averagefacility1 = helper::calculate_average_question_facility($questions[1]->id);
354
        $averagefacility2 = helper::calculate_average_question_facility($questions[2]->id);
355
        $averagefacility3 = helper::calculate_average_question_facility($questions[3]->id);
356
        $averagefacility4 = helper::calculate_average_question_facility($questions[4]->id);
357
 
358
        $this->assertEquals($expectedaveragefacilities[0], helper::format_percentage($averagefacility1));
359
        $this->assertEquals($expectedaveragefacilities[1], helper::format_percentage($averagefacility2));
360
        $this->assertEquals($expectedaveragefacilities[2], helper::format_percentage($averagefacility3));
361
        $this->assertEquals($expectedaveragefacilities[3], helper::format_percentage($averagefacility4));
362
 
363
        $this->assertDebuggingCalledCount(4,
364
            [
365
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
366
                    'in your question bank column class.',
367
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
368
                    'in your question bank column class.',
369
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
370
                    'in your question bank column class.',
371
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
372
                    'in your question bank column class.',
373
            ],
374
            [DEBUG_DEVELOPER, DEBUG_DEVELOPER, DEBUG_DEVELOPER, DEBUG_DEVELOPER]);
375
    }
376
 
377
    /**
378
     * Data provider for {@see test_load_question_discriminative_efficiency()}.
379
     * @return \Generator
380
     */
381
    public function load_question_discriminative_efficiency_provider(): \Generator {
382
        yield 'Discriminative efficiency' => [
383
            'Quiz 1 attempts' => [
384
                $this->generate_attempt_answers([1, 0, 0, 0]),
385
                $this->generate_attempt_answers([1, 1, 0, 0]),
386
                $this->generate_attempt_answers([1, 0, 1, 0]),
387
                $this->generate_attempt_answers([1, 1, 1, 1]),
388
            ],
389
            'Expected quiz 1 discriminative efficiency' => ['N/A', '33.33%', '33.33%', '100.00%'],
390
            'Quiz 2 attempts' => [
391
                $this->generate_attempt_answers([1, 1, 1, 1]),
392
                $this->generate_attempt_answers([0, 0, 0, 0]),
393
                $this->generate_attempt_answers([1, 0, 0, 1]),
394
                $this->generate_attempt_answers([0, 1, 1, 0]),
395
            ],
396
            'Expected quiz 2 discriminative efficiency' => ['50.00%', '50.00%', '50.00%', '50.00%'],
397
            'Expected average discriminative efficiency' => ['50.00%', '41.67%', '41.67%', '75.00%'],
398
        ];
399
    }
400
 
401
    /**
402
     * Test discriminative efficiency
403
     *
404
     * @dataProvider load_question_discriminative_efficiency_provider
405
     *
406
     * @param array $quiz1attempts quiz 1 attempts
407
     * @param array $expectedquiz1discriminativeefficiency expected quiz 1 discriminative efficiency
408
     * @param array $quiz2attempts quiz 2 attempts
409
     * @param array $expectedquiz2discriminativeefficiency expected quiz 2 discriminative efficiency
410
     * @param array $expectedaveragediscriminativeefficiency expected average discriminative efficiency
411
     * @deprecated since Moodle 4.3 please use the method from statistics_bulk_loader.
412
     * @todo MDL-78090 Final deprecation in Moodle 4.7
413
     */
414
    public function test_load_question_discriminative_efficiency(
415
        array $quiz1attempts,
416
        array $expectedquiz1discriminativeefficiency,
417
        array $quiz2attempts,
418
        array $expectedquiz2discriminativeefficiency,
419
        array $expectedaveragediscriminativeefficiency
420
    ): void {
421
        $this->resetAfterTest();
422
 
423
        list($quiz1, $quiz2, $questions) = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
424
 
425
        // Quiz 1 discriminative efficiency.
426
        $stats = $this->load_quiz_statistics_for_place(\context_module::instance($quiz1->cmid));
427
        $discriminativeefficiency1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminativeefficiency');
428
        $discriminativeefficiency2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminativeefficiency');
429
        $discriminativeefficiency3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminativeefficiency');
430
        $discriminativeefficiency4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminativeefficiency');
431
 
432
        $this->assertEquals($expectedquiz1discriminativeefficiency[0],
433
            helper::format_percentage($discriminativeefficiency1, false),
434
            "Failure in quiz 1 - question 1 discriminative efficiency");
435
        $this->assertEquals($expectedquiz1discriminativeefficiency[1],
436
            helper::format_percentage($discriminativeefficiency2, false),
437
            "Failure in quiz 1 - question 2 discriminative efficiency");
438
        $this->assertEquals($expectedquiz1discriminativeefficiency[2],
439
            helper::format_percentage($discriminativeefficiency3, false),
440
            "Failure in quiz 1 - question 3 discriminative efficiency");
441
        $this->assertEquals($expectedquiz1discriminativeefficiency[3],
442
            helper::format_percentage($discriminativeefficiency4, false),
443
            "Failure in quiz 1 - question 4 discriminative efficiency");
444
 
445
        // Quiz 2 discriminative efficiency.
446
        $stats = $this->load_quiz_statistics_for_place(\context_module::instance($quiz2->cmid));
447
        $discriminativeefficiency1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminativeefficiency');
448
        $discriminativeefficiency2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminativeefficiency');
449
        $discriminativeefficiency3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminativeefficiency');
450
        $discriminativeefficiency4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminativeefficiency');
451
 
452
        $this->assertEquals($expectedquiz2discriminativeefficiency[0],
453
            helper::format_percentage($discriminativeefficiency1, false),
454
            "Failure in quiz 2 - question 1 discriminative efficiency");
455
        $this->assertEquals($expectedquiz2discriminativeefficiency[1],
456
            helper::format_percentage($discriminativeefficiency2, false),
457
            "Failure in quiz 2 - question 2 discriminative efficiency");
458
        $this->assertEquals($expectedquiz2discriminativeefficiency[2],
459
            helper::format_percentage($discriminativeefficiency3, false),
460
            "Failure in quiz 2 - question 3 discriminative efficiency");
461
        $this->assertEquals($expectedquiz2discriminativeefficiency[3],
462
            helper::format_percentage($discriminativeefficiency4, false),
463
            "Failure in quiz 2 - question 4 discriminative efficiency");
464
 
465
        // Average question discriminative efficiency.
466
        $avgdiscriminativeefficiency1 = helper::calculate_average_question_discriminative_efficiency($questions[1]->id);
467
        $avgdiscriminativeefficiency2 = helper::calculate_average_question_discriminative_efficiency($questions[2]->id);
468
        $avgdiscriminativeefficiency3 = helper::calculate_average_question_discriminative_efficiency($questions[3]->id);
469
        $avgdiscriminativeefficiency4 = helper::calculate_average_question_discriminative_efficiency($questions[4]->id);
470
 
471
        $this->assertEquals($expectedaveragediscriminativeefficiency[0],
472
            helper::format_percentage($avgdiscriminativeefficiency1, false),
473
            "Failure in question 1 average discriminative efficiency");
474
        $this->assertEquals($expectedaveragediscriminativeefficiency[1],
475
            helper::format_percentage($avgdiscriminativeefficiency2, false),
476
            "Failure in question 2 average discriminative efficiency");
477
        $this->assertEquals($expectedaveragediscriminativeefficiency[2],
478
            helper::format_percentage($avgdiscriminativeefficiency3, false),
479
            "Failure in question 3 average discriminative efficiency");
480
        $this->assertEquals($expectedaveragediscriminativeefficiency[3],
481
            helper::format_percentage($avgdiscriminativeefficiency4, false),
482
            "Failure in question 4 average discriminative efficiency");
483
 
484
        $this->assertDebuggingCalledCount(4,
485
            [
486
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
487
                    'in your question bank column class.',
488
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
489
                    'in your question bank column class.',
490
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
491
                    'in your question bank column class.',
492
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
493
                    'in your question bank column class.',
494
            ],
495
            [DEBUG_DEVELOPER, DEBUG_DEVELOPER, DEBUG_DEVELOPER, DEBUG_DEVELOPER]);
496
    }
497
 
498
    /**
499
     * Data provider for {@see test_load_question_discrimination_index()}.
500
     * @return \Generator
501
     */
502
    public function load_question_discrimination_index_provider(): \Generator {
503
        yield 'Discrimination Index' => [
504
            'Quiz 1 attempts' => [
505
                $this->generate_attempt_answers([1, 0, 0, 0]),
506
                $this->generate_attempt_answers([1, 1, 0, 0]),
507
                $this->generate_attempt_answers([1, 0, 1, 0]),
508
                $this->generate_attempt_answers([1, 1, 1, 1]),
509
            ],
510
            'Expected quiz 1 Discrimination Index' => ['N/A', '30.15%', '30.15%', '81.65%'],
511
            'Quiz 2 attempts' => [
512
                $this->generate_attempt_answers([1, 1, 1, 1]),
513
                $this->generate_attempt_answers([0, 0, 0, 0]),
514
                $this->generate_attempt_answers([1, 0, 0, 1]),
515
                $this->generate_attempt_answers([0, 1, 1, 0]),
516
            ],
517
            'Expected quiz 2 discrimination Index' => ['44.72%', '44.72%', '44.72%', '44.72%'],
518
            'Expected average discrimination Index' => ['44.72%', '37.44%', '37.44%', '63.19%'],
519
        ];
520
    }
521
 
522
    /**
523
     * Test discrimination index
524
     *
525
     * @dataProvider load_question_discrimination_index_provider
526
     *
527
     * @param array $quiz1attempts quiz 1 attempts
528
     * @param array $expectedquiz1discriminationindex expected quiz 1 discrimination index
529
     * @param array $quiz2attempts quiz 2 attempts
530
     * @param array $expectedquiz2discriminationindex expected quiz 2 discrimination index
531
     * @param array $expectedaveragediscriminationindex expected average discrimination index
532
     * @deprecated since Moodle 4.3 please use the method from statistics_bulk_loader.
533
     * @todo MDL-78090 Final deprecation in Moodle 4.7
534
     */
535
    public function test_load_question_discrimination_index(
536
        array $quiz1attempts,
537
        array $expectedquiz1discriminationindex,
538
        array $quiz2attempts,
539
        array $expectedquiz2discriminationindex,
540
        array $expectedaveragediscriminationindex
541
    ): void {
542
        $this->resetAfterTest();
543
 
544
        list($quiz1, $quiz2, $questions) = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
545
 
546
        // Quiz 1 discrimination index.
547
        $stats = $this->load_quiz_statistics_for_place(\context_module::instance($quiz1->cmid));
548
        $discriminationindex1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminationindex');
549
        $discriminationindex2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminationindex');
550
        $discriminationindex3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminationindex');
551
        $discriminationindex4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminationindex');
552
 
553
        $this->assertEquals($expectedquiz1discriminationindex[0],
554
            helper::format_percentage($discriminationindex1, false),
555
            "Failure in quiz 1 - question 1 discrimination index");
556
        $this->assertEquals($expectedquiz1discriminationindex[1],
557
            helper::format_percentage($discriminationindex2, false),
558
            "Failure in quiz 1 - question 2 discrimination index");
559
        $this->assertEquals($expectedquiz1discriminationindex[2],
560
            helper::format_percentage($discriminationindex3, false),
561
            "Failure in quiz 1 - question 3 discrimination index");
562
        $this->assertEquals($expectedquiz1discriminationindex[3],
563
            helper::format_percentage($discriminationindex4, false),
564
            "Failure in quiz 1 - question 4 discrimination index");
565
 
566
        // Quiz 2 discrimination index.
567
        $stats = $this->load_quiz_statistics_for_place(\context_module::instance($quiz2->cmid));
568
        $discriminationindex1 = $this->extract_item_value($stats, $questions[1]->id, 'discriminationindex');
569
        $discriminationindex2 = $this->extract_item_value($stats, $questions[2]->id, 'discriminationindex');
570
        $discriminationindex3 = $this->extract_item_value($stats, $questions[3]->id, 'discriminationindex');
571
        $discriminationindex4 = $this->extract_item_value($stats, $questions[4]->id, 'discriminationindex');
572
 
573
        $this->assertEquals($expectedquiz2discriminationindex[0],
574
            helper::format_percentage($discriminationindex1, false),
575
            "Failure in quiz 2 - question 1 discrimination index");
576
        $this->assertEquals($expectedquiz2discriminationindex[1],
577
            helper::format_percentage($discriminationindex2, false),
578
            "Failure in quiz 2 - question 2 discrimination index");
579
        $this->assertEquals($expectedquiz2discriminationindex[2],
580
            helper::format_percentage($discriminationindex3, false),
581
            "Failure in quiz 2 - question 3 discrimination index");
582
        $this->assertEquals($expectedquiz2discriminationindex[3],
583
            helper::format_percentage($discriminationindex4, false),
584
            "Failure in quiz 2 - question 4 discrimination index");
585
 
586
        // Average question discrimination index.
587
        $avgdiscriminationindex1 = helper::calculate_average_question_discrimination_index($questions[1]->id);
588
        $avgdiscriminationindex2 = helper::calculate_average_question_discrimination_index($questions[2]->id);
589
        $avgdiscriminationindex3 = helper::calculate_average_question_discrimination_index($questions[3]->id);
590
        $avgdiscriminationindex4 = helper::calculate_average_question_discrimination_index($questions[4]->id);
591
 
592
        $this->assertEquals($expectedaveragediscriminationindex[0],
593
            helper::format_percentage($avgdiscriminationindex1, false),
594
            "Failure in question 1 average discrimination index");
595
        $this->assertEquals($expectedaveragediscriminationindex[1],
596
            helper::format_percentage($avgdiscriminationindex2, false),
597
            "Failure in question 2 average discrimination index");
598
        $this->assertEquals($expectedaveragediscriminationindex[2],
599
            helper::format_percentage($avgdiscriminationindex3, false),
600
            "Failure in question 3 average discrimination index");
601
        $this->assertEquals($expectedaveragediscriminationindex[3],
602
            helper::format_percentage($avgdiscriminationindex4, false),
603
            "Failure in question 4 average discrimination index");
604
 
605
        $this->assertDebuggingCalledCount(4,
606
            [
607
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
608
                    'in your question bank column class.',
609
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
610
                    'in your question bank column class.',
611
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
612
                    'in your question bank column class.',
613
                'Deprecated: please use statistics_bulk_loader instead, or get_required_statistics_fields ' .
614
                    'in your question bank column class.',
615
            ],
616
            [DEBUG_DEVELOPER, DEBUG_DEVELOPER, DEBUG_DEVELOPER, DEBUG_DEVELOPER]);
617
    }
618
}