Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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 core_course;
18
 
19
defined('MOODLE_INTERNAL') || die();
20
global $CFG;
21
 
22
require_once($CFG->dirroot . '/completion/criteria/completion_criteria.php');
23
require_once($CFG->dirroot . '/completion/criteria/completion_criteria_activity.php');
24
require_once($CFG->dirroot . '/lib/grade/grade_item.php');
25
require_once($CFG->dirroot . '/lib/grade/grade_grade.php');
26
require_once($CFG->dirroot . '/lib/grade/grade_category.php');
27
require_once($CFG->dirroot . '/lib/grade/constants.php');
28
 
29
/**
30
 * Unit tests for core targets.
31
 *
32
 * @package   core_course
33
 * @copyright 2019 Victor Deniz <victor@moodle.com>
34
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
class targets_test extends \advanced_testcase {
37
 
38
    /**
39
     * Provides course params for the {@link self::test_core_target_course_completion_analysable()} method.
40
     *
41
     * @return array
42
     */
43
    public function analysable_provider() {
44
 
45
        $now = new \DateTime("now", \core_date::get_server_timezone_object());
46
        $year = $now->format('Y');
47
        $month = $now->format('m');
48
 
49
        return [
50
            'coursenotyetstarted' => [
51
                'params' => [
52
                    'enablecompletion' => 1,
53
                    'startdate' => mktime(0, 0, 0, 10, 24, $year + 1)
54
                ],
55
                'isvalid' => get_string('coursenotyetstarted', 'course')
56
            ],
57
            'coursenostudents' => [
58
                'params' => [
59
                    'enablecompletion' => 1,
60
                    'startdate' => mktime(0, 0, 0, 10, 24, $year - 2),
61
                    'enddate' => mktime(0, 0, 0, 10, 24, $year - 1)
62
                ],
63
                'isvalid' => get_string('nocoursestudents', 'course')
64
            ],
65
            'coursenosections' => [
66
                'params' => [
67
                    'enablecompletion' => 1,
68
                    'format' => 'social',
69
                    'students' => true
70
                ],
71
                'isvalid' => get_string('nocoursesections', 'course')
72
            ],
73
            'coursenoendtime' => [
74
                'params' => [
75
                    'enablecompletion' => 1,
76
                    'format' => 'topics',
77
                    'enddate' => 0,
78
                    'students' => true
79
                ],
80
                'isvalid' => get_string('nocourseendtime', 'course')
81
            ],
82
            'courseendbeforestart' => [
83
                'params' => [
84
                    'enablecompletion' => 1,
85
                    'enddate' => mktime(0, 0, 0, 10, 23, $year - 2),
86
                    'students' => true
87
                ],
88
                'isvalid' => get_string('errorendbeforestart', 'course')
89
            ],
90
            'coursetoolong' => [
91
                'params' => [
92
                    'enablecompletion' => 1,
93
                    'startdate' => mktime(0, 0, 0, 10, 24, $year - 2),
94
                    'enddate' => mktime(0, 0, 0, 10, 23, $year),
95
                    'students' => true
96
                ],
97
                'isvalid' => get_string('coursetoolong', 'course')
98
            ],
99
            'coursealreadyfinished' => [
100
                'params' => [
101
                    'enablecompletion' => 1,
102
                    'startdate' => mktime(0, 0, 0, 10, 24, $year - 2),
103
                    'enddate' => mktime(0, 0, 0, 10, 23, $year - 1),
104
                    'students' => true
105
                ],
106
                'isvalid' => get_string('coursealreadyfinished', 'course'),
107
                'fortraining' => false
108
            ],
109
            'coursenotyetfinished' => [
110
                'params' => [
111
                    'enablecompletion' => 1,
112
                    'startdate' => mktime(0, 0, 0, $month - 1, 24, $year),
113
                    'enddate' => mktime(0, 0, 0, $month + 2, 23, $year),
114
                    'students' => true
115
                ],
116
                'isvalid' => get_string('coursenotyetfinished', 'course')
117
            ],
118
            'coursenocompletion' => [
119
                'params' => [
120
                    'enablecompletion' => 0,
121
                    'startdate' => mktime(0, 0, 0, $month - 2, 24, $year),
122
                    'enddate' => mktime(0, 0, 0, $month - 1, 23, $year),
123
                    'students' => true
124
                ],
125
                'isvalid' => get_string('completionnotenabledforcourse', 'completion')
126
            ],
127
            'coursehiddentraining' => [
128
                'params' => [
129
                    'enablecompletion' => 1,
130
                    'startdate' => mktime(0, 0, 0, $month - 1, 24, $year - 1),
131
                    'enddate' => mktime(0, 0, 0, $month - 1, 23, $year),
132
                    'students' => true,
133
                    'visible' => '0',
134
                ],
135
                'isvalid' => true,
136
            ],
137
            'coursehiddenprediction' => [
138
                'params' => [
139
                    'enablecompletion' => 1,
140
                    'startdate' => mktime(0, 0, 0, $month - 1, 24, $year),
141
                    'enddate' => mktime(0, 0, 0, $month - 1, 23, $year + 1),
142
                    'students' => true,
143
                    'visible' => '0',
144
                ],
145
                'isvalid' => get_string('hiddenfromstudents'),
146
                'fortraining' => false
147
            ],
148
        ];
149
    }
150
 
151
    /**
152
     * Provides enrolment params for the {@link self::test_core_target_course_completion_samples()} method.
153
     *
154
     * @return array
155
     */
156
    public function sample_provider() {
157
        $now = time();
158
        return [
159
            'enrolmentendbeforecourse' => [
160
                'coursestart' => $now,
161
                'courseend' => $now + (WEEKSECS * 8),
162
                'timestart' => $now,
163
                'timeend' => $now - DAYSECS,
164
                'isvalidfortraining' => false,
165
                'isvalidforprediction' => false
166
            ],
167
            'enrolmenttoolong' => [
168
                'coursestart' => $now,
169
                'courseend' => $now + (WEEKSECS * 8),
170
                'timestart' => $now - (YEARSECS + (WEEKSECS * 8)),
171
                'timeend' => $now + (WEEKSECS * 8),
172
                'isvalidfortraining' => false,
173
                'isvalidforprediction' => false
174
            ],
175
            'enrolmentstartaftercourse' => [
176
                'coursestart' => $now,
177
                'courseend' => $now + (WEEKSECS * 8),
178
                'timestart' => $now + (WEEKSECS * 9),
179
                'timeend' => $now + (WEEKSECS * 10),
180
                'isvalidfortraining' => false,
181
                'isvalidforprediction' => false
182
            ],
183
            'enrolmentstartsafternow' => [
184
                'coursestart' => $now,
185
                'courseend' => $now + (WEEKSECS * 8),
186
                'timestart' => $now + (WEEKSECS * 2),
187
                'timeend' => $now + (WEEKSECS * 7),
188
                'isvalidfortraining' => false,
189
                'isvalidforprediction' => false
190
            ],
191
            'enrolmentfinishedbeforenow' => [
192
                'coursestart' => $now - (WEEKSECS * 4),
193
                'courseend' => $now - (WEEKSECS * 1),
194
                'timestart' => $now - (WEEKSECS * 3),
195
                'timeend' => $now - (WEEKSECS * 2),
196
                'isvalidfortraining' => true,
197
                'isvalidforprediction' => false
198
            ],
199
        ];
200
    }
201
 
202
    /**
203
     * Provides enrolment params for the {@link self::test_core_target_course_completion_samples()} method.
204
     *
205
     * @return array
206
     */
207
    public function active_during_analysis_time_provider() {
208
        $now = time();
209
 
210
        return [
211
            'enrol-after-end' => [
212
                'starttime' => $now,
213
                'endtime' => $now + WEEKSECS,
214
                'timestart' => $now + (WEEKSECS * 2),
215
                'timeend' => $now + (WEEKSECS * 3),
216
                'nullcalculation' => true,
217
            ],
218
            'enrol-before-start' => [
219
                'starttime' => $now + (WEEKSECS * 2),
220
                'endtime' => $now + (WEEKSECS * 3),
221
                'timestart' => $now,
222
                'timeend' => $now + WEEKSECS,
223
                'nullcalculation' => true,
224
            ],
225
            'enrol-active-exact-match' => [
226
                'starttime' => $now,
227
                'endtime' => $now + (WEEKSECS * 1),
228
                'timestart' => $now,
229
                'timeend' => $now + (WEEKSECS * 1),
230
                'nullcalculation' => false,
231
            ],
232
            'enrol-active' => [
233
                'starttime' => $now + WEEKSECS,
234
                'endtime' => $now + (WEEKSECS * 2),
235
                'timestart' => $now,
236
                'timeend' => $now + (WEEKSECS * 3),
237
                'nullcalculation' => false,
238
            ],
239
            'enrol-during-analysis-active-just-for-a-while' => [
240
                'starttime' => $now,
241
                'endtime' => $now + (WEEKSECS * 10),
242
                'timestart' => $now + WEEKSECS,
243
                'timeend' => $now + (WEEKSECS * 2),
244
                'nullcalculation' => true,
245
            ],
246
            'enrol-during-analysis-mostly-active' => [
247
                'starttime' => $now,
248
                'endtime' => $now + (WEEKSECS * 20),
249
                'timestart' => $now + WEEKSECS,
250
                'timeend' => $now + (WEEKSECS * 19),
251
                'nullcalculation' => false,
252
            ],
253
            'enrol-partly-active-starts-before' => [
254
                'starttime' => $now + WEEKSECS,
255
                'endtime' => $now + (WEEKSECS * 10),
256
                'timestart' => $now,
257
                'timeend' => $now + (WEEKSECS * 2),
258
                'nullcalculation' => true,
259
            ],
260
            'enrol-mostly-active-starts-before' => [
261
                'starttime' => $now + WEEKSECS,
262
                'endtime' => $now + (WEEKSECS * 10),
263
                'timestart' => $now,
264
                'timeend' => $now + (WEEKSECS * 9),
265
                'nullcalculation' => false,
266
            ],
267
            'enrol-partly-active-ends-afterwards' => [
268
                'starttime' => $now,
269
                'endtime' => $now + (WEEKSECS * 10),
270
                'timestart' => $now + (WEEKSECS * 9),
271
                'timeend' => $now + (WEEKSECS * 11),
272
                'nullcalculation' => true,
273
            ],
274
            'enrol-mostly-active-ends-afterwards' => [
275
                'starttime' => $now,
276
                'endtime' => $now + (WEEKSECS * 10),
277
                'timestart' => $now + WEEKSECS,
278
                'timeend' => $now + (WEEKSECS * 11),
279
                'nullcalculation' => false,
280
            ],
281
            'enrol-partly-active-no-enrolment-end' => [
282
                'starttime' => $now,
283
                'endtime' => $now + (WEEKSECS * 10),
284
                'timestart' => $now + (WEEKSECS * 9),
285
                'timeend' => false,
286
                'nullcalculation' => true,
287
            ],
288
            'enrol-mostly-active-no-enrolment-end-false' => [
289
                'starttime' => $now,
290
                'endtime' => $now + (WEEKSECS * 10),
291
                'timestart' => $now + WEEKSECS,
292
                'timeend' => false,
293
                'nullcalculation' => false,
294
            ],
295
            'enrol-mostly-active-no-enrolment-end-zero' => [
296
                'starttime' => $now,
297
                'endtime' => $now + (WEEKSECS * 10),
298
                'timestart' => $now + WEEKSECS,
299
                'timeend' => 0,
300
                'nullcalculation' => false,
301
            ],
302
            'enrol-no-enrolment-start-false' => [
303
                'starttime' => $now,
304
                'endtime' => $now + (WEEKSECS * 10),
305
                'timestart' => false,
306
                'timeend' => $now + (WEEKSECS * 9),
307
                'nullcalculation' => false,
308
            ],
309
            'enrol-no-enrolment-start-zero' => [
310
                'starttime' => $now,
311
                'endtime' => $now + (WEEKSECS * 10),
312
                'timestart' => 0,
313
                'timeend' => $now + (WEEKSECS * 9),
314
                'nullcalculation' => false,
315
            ],
316
            'no-start' => [
317
                'starttime' => 0,
318
                'endtime' => $now + (WEEKSECS * 2),
319
                'timestart' => $now + WEEKSECS,
320
                'timeend' => $now + (WEEKSECS * 3),
321
                'nullcalculation' => false,
322
            ],
323
            'no-end' => [
324
                'starttime' => $now,
325
                'endtime' => 0,
326
                'timestart' => $now + (WEEKSECS * 2),
327
                'timeend' => $now + (WEEKSECS * 3),
328
                'nullcalculation' => false,
329
            ]
330
        ];
331
    }
332
 
333
    /**
334
     * Test the conditions of a valid analysable, both common and specific to this target (course_completion).
335
     *
336
     * @dataProvider analysable_provider
337
     * @param mixed $courseparams Course data
338
     * @param true|string $isvalid True when analysable is valid, string when it is not
339
     * @param boolean $fortraining True if the course is for training the model
340
     */
11 efrain 341
    public function test_core_target_course_completion_analysable($courseparams, $isvalid, $fortraining = true): void {
1 efrain 342
        global $DB;
343
 
344
        $this->resetAfterTest(true);
345
 
346
        try {
347
            $course = $this->getDataGenerator()->create_course($courseparams);
348
        } catch (\moodle_exception $e) {
349
            $course = $this->getDataGenerator()->create_course();
350
            $courserecord = $courseparams;
351
            $courserecord['id'] = $course->id;
352
            unset($courserecord['students']);
353
 
354
            $DB->update_record_raw('course', $courserecord);
355
            $course = get_course($course->id);
356
        }
357
        $user = $this->getDataGenerator()->create_user();
358
 
359
        if (!empty($courseparams['enablecompletion'])) {
360
            $assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'completion' => 1]);
361
            $cm = get_coursemodule_from_id('assign', $assign->cmid);
362
 
363
            $criteriadata = (object) [
364
                'id' => $course->id,
365
                'criteria_activity' => [
366
                    $cm->id => 1
367
                ]
368
            ];
369
            $criterion = new \completion_criteria_activity();
370
            $criterion->update_config($criteriadata);
371
        }
372
 
373
        $target = new \core_course\analytics\target\course_completion();
374
 
375
        // Test valid analysables.
376
 
377
        if (!empty($courseparams['students'])) {
378
            // Enroll user in course.
379
            $this->getDataGenerator()->enrol_user($user->id, $course->id);
380
        }
381
 
382
        $analysable = new \core_analytics\course($course);
383
        $this->assertEquals($isvalid, $target->is_valid_analysable($analysable, $fortraining));
384
    }
385
 
386
    /**
387
     * Test the conditions of a valid sample, both common and specific to this target (course_completion).
388
     *
389
     * @dataProvider sample_provider
390
     * @param int $coursestart Course start date
391
     * @param int $courseend Course end date
392
     * @param int $timestart Enrol start date
393
     * @param int $timeend Enrol end date
394
     * @param boolean $isvalidfortraining True when sample is valid for training, false when it is not
395
     * @param boolean $isvalidforprediction True when sample is valid for prediction, false when it is not
396
     */
397
    public function test_core_target_course_completion_samples($coursestart, $courseend, $timestart, $timeend,
11 efrain 398
            $isvalidfortraining, $isvalidforprediction): void {
1 efrain 399
 
400
        $this->resetAfterTest(true);
401
 
402
        $courserecord = new \stdClass();
403
        $courserecord->startdate = $coursestart;
404
        $courserecord->enddate = $courseend;
405
 
406
        $user = $this->getDataGenerator()->create_user();
407
        $course = $this->getDataGenerator()->create_course($courserecord);
408
        $this->getDataGenerator()->enrol_user($user->id, $course->id, null, 'manual', $timestart, $timeend);
409
 
410
        $target = new \core_course\analytics\target\course_completion();
411
        $analyser = new \core\analytics\analyser\student_enrolments(1, $target, [], [], []);
412
        $analysable = new \core_analytics\course($course);
413
 
414
        $class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
415
        $method = $class->getMethod('get_all_samples');
416
 
417
        list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
418
        $target->add_sample_data($samplesdata);
419
        $sampleid = reset($sampleids);
420
 
421
        $this->assertEquals($isvalidfortraining, $target->is_valid_sample($sampleid, $analysable, true));
422
        $this->assertEquals($isvalidforprediction, $target->is_valid_sample($sampleid, $analysable, false));
423
    }
424
 
425
    /**
426
     * Test the conditions of a valid calculation (course_completion).
427
     *
428
     * @dataProvider active_during_analysis_time_provider
429
     * @param int $starttime Analysis start time
430
     * @param int $endtime Analysis end time
431
     * @param int $timestart Enrol start date
432
     * @param int $timeend Enrol end date
433
     * @param boolean $nullcalculation Whether the calculation should be null or not
434
     */
435
    public function test_core_target_course_completion_active_during_analysis_time($starttime, $endtime, $timestart, $timeend,
11 efrain 436
            $nullcalculation): void {
1 efrain 437
 
438
        $this->resetAfterTest(true);
439
 
440
        $user = $this->getDataGenerator()->create_user();
441
        $course = $this->getDataGenerator()->create_course();
442
        $this->getDataGenerator()->enrol_user($user->id, $course->id, null, 'manual', $timestart, $timeend);
443
 
444
        $target = new \core_course\analytics\target\course_completion();
445
        $analyser = new \core\analytics\analyser\student_enrolments(1, $target, [], [], []);
446
        $analysable = new \core_analytics\course($course);
447
 
448
        $class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
449
        $method = $class->getMethod('get_all_samples');
450
 
451
        list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
452
        $target->add_sample_data($samplesdata);
453
        $sampleid = reset($sampleids);
454
 
455
        $reftarget = new \ReflectionObject($target);
456
        $refmethod = $reftarget->getMethod('calculate_sample');
457
 
458
        if ($nullcalculation) {
459
            $this->assertNull($refmethod->invoke($target, $sampleid, $analysable, $starttime, $endtime));
460
        } else {
461
            $this->assertNotNull($refmethod->invoke($target, $sampleid, $analysable, $starttime, $endtime));
462
        }
463
    }
464
 
465
    /**
466
     * Setup user, framework, competencies and course competencies.
467
     */
468
    protected function setup_competencies_environment() {
469
        $this->resetAfterTest(true);
470
        $now = time();
471
        $this->setAdminUser();
472
        $dg = $this->getDataGenerator();
473
        $lpg = $dg->get_plugin_generator('core_competency');
474
 
475
        $course = $dg->create_course(array('startdate' => $now - WEEKSECS, 'enddate' => $now - DAYSECS));
476
        $coursenocompetencies = $dg->create_course(array('startdate' => $now - WEEKSECS, 'enddate' => $now - DAYSECS));
477
 
478
        $u1 = $dg->create_user();
479
        $this->getDataGenerator()->enrol_user($u1->id, $course->id);
480
        $this->getDataGenerator()->enrol_user($u1->id, $coursenocompetencies->id);
481
        $f1 = $lpg->create_framework();
482
        $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
483
        $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
484
        $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
485
        $c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
486
        $cc1 = $lpg->create_course_competency(array('competencyid' => $c1->get('id'), 'courseid' => $course->id,
487
            'ruleoutcome' => \core_competency\course_competency::OUTCOME_NONE));
488
        $cc2 = $lpg->create_course_competency(array('competencyid' => $c2->get('id'), 'courseid' => $course->id,
489
            'ruleoutcome' => \core_competency\course_competency::OUTCOME_EVIDENCE));
490
        $cc3 = $lpg->create_course_competency(array('competencyid' => $c3->get('id'), 'courseid' => $course->id,
491
            'ruleoutcome' => \core_competency\course_competency::OUTCOME_RECOMMEND));
492
        $cc4 = $lpg->create_course_competency(array('competencyid' => $c4->get('id'), 'courseid' => $course->id,
493
            'ruleoutcome' => \core_competency\course_competency::OUTCOME_COMPLETE));
494
 
495
        return array(
496
            'course' => $course,
497
            'coursenocompetencies' => $coursenocompetencies,
498
            'user' => $u1,
499
            'course_competencies' => array($cc1, $cc2, $cc3, $cc4)
500
        );
501
    }
502
 
503
     /**
504
      * Test the specific conditions of a valid analysable for the course_competencies target.
505
      */
11 efrain 506
    public function test_core_target_course_competencies_analysable(): void {
1 efrain 507
 
508
        $data = $this->setup_competencies_environment();
509
 
510
        $analysable = new \core_analytics\course($data['course']);
511
        $target = new \core_course\analytics\target\course_competencies();
512
 
513
        $this->assertTrue($target->is_valid_analysable($analysable));
514
 
515
        $analysable = new \core_analytics\course($data['coursenocompetencies']);
516
        $this->assertEquals(get_string('nocompetenciesincourse', 'tool_lp'), $target->is_valid_analysable($analysable));
517
    }
518
 
519
    /**
520
     * Test the target value calculation.
521
     */
11 efrain 522
    public function test_core_target_course_competencies_calculate(): void {
1 efrain 523
 
524
        $data = $this->setup_competencies_environment();
525
 
526
        $target = new \core_course\analytics\target\course_competencies();
527
        $analyser = new \core\analytics\analyser\student_enrolments(1, $target, [], [], []);
528
        $analysable = new \core_analytics\course($data['course']);
529
 
530
        $class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
531
        $method = $class->getMethod('get_all_samples');
532
 
533
        list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
534
        $target->add_sample_data($samplesdata);
535
        $sampleid = reset($sampleids);
536
 
537
        $class = new \ReflectionClass('\core_course\analytics\target\course_competencies');
538
        $method = $class->getMethod('calculate_sample');
539
 
540
        // Method calculate_sample() returns 1 when the user has not achieved all the competencies assigned to the course.
541
        $this->assertEquals(1, $method->invoke($target, $sampleid, $analysable));
542
 
543
        // Grading of all the competences assigned to the course, in such way that the user achieves them all.
544
        foreach ($data['course_competencies'] as $competency) {
545
            \core_competency\api::grade_competency_in_course($data['course']->id, $data['user']->id,
546
                    $competency->get('competencyid'), 3, 'Unit test');
547
        }
548
        // Method calculate_sample() returns 0 when the user has achieved all the competencies assigned to the course.
549
        $this->assertEquals(0, $method->invoke($target, $sampleid, $analysable));
550
    }
551
 
552
    /**
553
     * Test the specific conditions of a valid analysable for the course_gradetopass target.
554
     */
11 efrain 555
    public function test_core_target_course_gradetopass_analysable(): void {
1 efrain 556
        global $DB;
557
 
558
        $this->resetAfterTest(true);
559
        $now = time();
560
 
561
        $dg = $this->getDataGenerator();
562
 
563
        // Course without grade to pass set.
564
        $course1 = $dg->create_course(array('startdate' => $now - WEEKSECS, 'enddate' => $now - DAYSECS));
565
        $student1 = $dg->create_user();
566
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
567
        $dg->enrol_user($student1->id, $course1->id, $studentrole->id);
568
 
569
        $analysable = new \core_analytics\course($course1);
570
        $target = new \core_course\analytics\target\course_gradetopass();
571
        $this->assertEquals(get_string('gradetopassnotset', 'course'), $target->is_valid_analysable($analysable));
572
 
573
        // Set grade to pass.
574
        $courseitem = \grade_item::fetch_course_item($course1->id);
575
        $courseitem->gradepass = 50;
576
        $DB->update_record('grade_items', $courseitem);
577
        // Since the grade to pass value is cached in the target, a new one it is instanciated.
578
        $target = new \core_course\analytics\target\course_gradetopass();
579
        $this->assertTrue($target->is_valid_analysable($analysable));
580
 
581
    }
582
 
583
    /**
584
     * Test the target value calculation of the course_gradetopass target.
585
     */
11 efrain 586
    public function test_core_target_course_gradetopass_calculate(): void {
1 efrain 587
        global $DB;
588
 
589
        $this->resetAfterTest(true);
590
 
591
        $dg = $this->getDataGenerator();
592
        $course1 = $dg->create_course();
593
        // Set grade to pass.
594
        $student1 = $dg->create_user();
595
        $student2 = $dg->create_user();
596
        $student3 = $dg->create_user();
597
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
598
        $dg->enrol_user($student1->id, $course1->id, $studentrole->id);
599
        $dg->enrol_user($student2->id, $course1->id, $studentrole->id);
600
        $dg->enrol_user($student3->id, $course1->id, $studentrole->id);
601
 
602
        // get_all_samples() does not guarantee any order, so let's
603
        // explicitly define the expectations here for later comparing.
604
        // Expectations format being array($userid => expectation, ...)
605
        $expectations = [];
606
 
607
        $courseitem = \grade_item::fetch_course_item($course1->id);
608
        // Student1 (< gradepass) fails, so it's non achieved sample.
609
        $courseitem->update_final_grade($student1->id, 30);
610
        $expectations[$student1->id] = 1;
611
 
612
        // Student2 (> gradepass) passes, so it's achieved sample.
613
        $courseitem->update_final_grade($student2->id, 60);
614
        $expectations[$student2->id] = 0;
615
 
616
        // Student 3 (has no grade) fails, so it's non achieved sample.
617
        $expectations[$student3->id] = 1;
618
 
619
        $courseitem->gradepass = 50;
620
        $DB->update_record('grade_items', $courseitem);
621
 
622
        $target = new \core_course\analytics\target\course_gradetopass();
623
        $analyser = new \core\analytics\analyser\student_enrolments(1, $target, [], [], []);
624
        $analysable = new \core_analytics\course($course1);
625
 
626
        $class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
627
        $method = $class->getMethod('get_all_samples');
628
 
629
        list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
630
        $target->add_sample_data($samplesdata);
631
 
632
        $class = new \ReflectionClass('\core_course\analytics\target\course_gradetopass');
633
        $method = $class->getMethod('calculate_sample');
634
 
635
        // Verify all the expectations are fulfilled.
636
        foreach ($sampleids as $sampleid => $key) {
637
            $this->assertEquals($expectations[$samplesdata[$key]['user']->id], $method->invoke($target, $sampleid, $analysable));
638
        }
639
    }
640
}