Rev 1 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?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/>./*** mod_h5pactivity grader tests** @package mod_h5pactivity* @category test* @copyright 2020 Ferran Recio <ferran@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/namespace mod_h5pactivity\local;use grade_item;use stdClass;/*** Grader tests class for mod_h5pactivity.** @package mod_h5pactivity* @category test* @copyright 2020 Ferran Recio <ferran@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class grader_test extends \advanced_testcase {/*** Setup to ensure that fixtures are loaded.*/public static function setupBeforeClass(): void {global $CFG;require_once($CFG->libdir.'/gradelib.php');}/*** Test for grade item delete.*/public function test_grade_item_delete(): void {$this->resetAfterTest();$this->setAdminUser();$course = $this->getDataGenerator()->create_course();$activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);$user = $this->getDataGenerator()->create_and_enrol($course, 'student');$grader = new grader($activity);// Force a user grade.$this->generate_fake_attempt($activity, $user, 5, 10);$grader->update_grades($user->id);$gradeinfo = grade_get_grades($course->id, 'mod', 'h5pactivity', $activity->id, $user->id);$this->assertNotEquals(0, count($gradeinfo->items));$this->assertArrayHasKey($user->id, $gradeinfo->items[0]->grades);$grader->grade_item_delete();$gradeinfo = grade_get_grades($course->id, 'mod', 'h5pactivity', $activity->id, $user->id);$this->assertEquals(0, count($gradeinfo->items));}/*** Test for grade item update.** @dataProvider grade_item_update_data* @param int $newgrade new activity grade* @param bool $reset if has to reset grades* @param string $idnumber the new idnumber*/public function test_grade_item_update(int $newgrade, bool $reset, string $idnumber): void {$this->resetAfterTest();$this->setAdminUser();$course = $this->getDataGenerator()->create_course();$activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);$user = $this->getDataGenerator()->create_and_enrol($course, 'student');// Force a user initial grade.$grader = new grader($activity);$this->generate_fake_attempt($activity, $user, 5, 10);$grader->update_grades($user->id);$gradeinfo = grade_get_grades($course->id, 'mod', 'h5pactivity', $activity->id, $user->id);$this->assertNotEquals(0, count($gradeinfo->items));$item = array_shift($gradeinfo->items);$this->assertArrayHasKey($user->id, $item->grades);$this->assertEquals(50, round($item->grades[$user->id]->grade));// Module grade value determine the way gradebook acts. That means that the expected// result depends on this value.// - Grade > 0: regular max grade value.// - Grade = 0: no grading is used (but grademax remains the same).// - Grade < 0: a scaleid is used (value = -scaleid).if ($newgrade > 0) {$grademax = $newgrade;$scaleid = null;$usergrade = ($newgrade > 50) ? 50 : $newgrade;} else if ($newgrade == 0) {$grademax = 100;$scaleid = null;$usergrade = null; // No user grades expected.} else if ($newgrade < 0) {$scale = $this->getDataGenerator()->create_scale(array("scale" => "value1, value2, value3"));$newgrade = -1 * $scale->id;$grademax = 3;$scaleid = $scale->id;$usergrade = 3; // 50 value will ve converted to "value 3" on scale.}// Update grade item.$activity->grade = $newgrade;// In case a reset is need, usergrade will be empty.if ($reset) {$param = 'reset';$usergrade = null;} else {// Individual user gradings will be tested as a subcall of update_grades.$param = null;}$grader = new grader($activity, $idnumber);$grader->grade_item_update($param);// Check new grade item and grades.$gradeinfo = grade_get_grades($course->id, 'mod', 'h5pactivity', $activity->id, $user->id);$item = array_shift($gradeinfo->items);$this->assertEquals($scaleid, $item->scaleid);$this->assertEquals($grademax, $item->grademax);$this->assertArrayHasKey($user->id, $item->grades);if ($usergrade) {$this->assertEquals($usergrade, round($item->grades[$user->id]->grade));} else {$this->assertEmpty($item->grades[$user->id]->grade);}if (!empty($idnumber)) {$gradeitem = grade_item::fetch(['idnumber' => $idnumber, 'courseid' => $course->id]);$this->assertInstanceOf('grade_item', $gradeitem);}}/*** Data provider for test_grade_item_update.** @return array*/public function grade_item_update_data(): array {return ['Change idnumber' => [100, false, 'newidnumber'],'Increase max grade to 110' => [110, false, ''],'Decrease max grade to 80' => [40, false, ''],'Decrease max grade to 40 (less than actual grades)' => [40, false, ''],'Reset grades' => [100, true, ''],'Disable grades' => [0, false, ''],'Use scales' => [-1, false, ''],'Use scales with reset' => [-1, true, ''],];}/*** Test for grade update.** @dataProvider update_grades_data* @param int $newgrade the new activity grade* @param bool $all if has to be applied to all students or just to one* @param int $completion 1 all student have the activity completed, 0 one have incompleted* @param array $results expected results (user1 grade, user2 grade)*/public function test_update_grades(int $newgrade, bool $all, int $completion, array $results): void {$this->resetAfterTest();$this->setAdminUser();$course = $this->getDataGenerator()->create_course();$activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);$user1 = $this->getDataGenerator()->create_and_enrol($course, 'student');$user2 = $this->getDataGenerator()->create_and_enrol($course, 'student');// Force a user initial grade.$grader = new grader($activity);$this->generate_fake_attempt($activity, $user1, 5, 10);$this->generate_fake_attempt($activity, $user2, 3, 12, $completion);$grader->update_grades();$gradeinfo = grade_get_grades($course->id, 'mod', 'h5pactivity', $activity->id, [$user1->id, $user2->id]);$this->assertNotEquals(0, count($gradeinfo->items));$item = array_shift($gradeinfo->items);$this->assertArrayHasKey($user1->id, $item->grades);$this->assertArrayHasKey($user2->id, $item->grades);$this->assertEquals(50, $item->grades[$user1->id]->grade);// Uncompleted attempts does not generate grades.if ($completion) {$this->assertEquals(25, $item->grades[$user2->id]->grade);} else {$this->assertNull($item->grades[$user2->id]->grade);}// Module grade value determine the way gradebook acts. That means that the expected// result depends on this value.// - Grade > 0: regular max grade value.// - Grade <= 0: no grade calculation is used (scale and no grading).if ($newgrade < 0) {$scale = $this->getDataGenerator()->create_scale(array("scale" => "value1, value2, value3"));$activity->grade = -1 * $scale->id;} else {$activity->grade = $newgrade;}$userid = ($all) ? 0 : $user1->id;$grader = new grader($activity);$grader->update_grades($userid);// Check new grade item and grades.$gradeinfo = grade_get_grades($course->id, 'mod', 'h5pactivity', $activity->id, [$user1->id, $user2->id]);$item = array_shift($gradeinfo->items);$this->assertArrayHasKey($user1->id, $item->grades);$this->assertArrayHasKey($user2->id, $item->grades);$this->assertEquals($results[0], $item->grades[$user1->id]->grade);$this->assertEquals($results[1], $item->grades[$user2->id]->grade);}/*** Data provider for test_grade_item_update.** @return array*/public function update_grades_data(): array {return [// Quantitative grade, all attempts completed.'Same grademax, all users, all completed' => [100, true, 1, [50, 25]],'Same grademax, one user, all completed' => [100, false, 1, [50, 25]],'Increade max, all users, all completed' => [200, true, 1, [100, 50]],'Increade max, one user, all completed' => [200, false, 1, [100, 25]],'Decrease max, all users, all completed' => [50, true, 1, [25, 12.5]],'Decrease max, one user, all completed' => [50, false, 1, [25, 25]],// Quantitative grade, some attempts not completed.'Same grademax, all users, not completed' => [100, true, 0, [50, null]],'Same grademax, one user, not completed' => [100, false, 0, [50, null]],'Increade max, all users, not completed' => [200, true, 0, [100, null]],'Increade max, one user, not completed' => [200, false, 0, [100, null]],'Decrease max, all users, not completed' => [50, true, 0, [25, null]],'Decrease max, one user, not completed' => [50, false, 0, [25, null]],// No grade (no grade will be used).'No grade, all users, all completed' => [0, true, 1, [null, null]],'No grade, one user, all completed' => [0, false, 1, [null, null]],'No grade, all users, not completed' => [0, true, 0, [null, null]],'No grade, one user, not completed' => [0, false, 0, [null, null]],// Scale (grate item will updated but without regrading).'Scale, all users, all completed' => [-1, true, 1, [3, 3]],'Scale, one user, all completed' => [-1, false, 1, [3, 3]],'Scale, all users, not completed' => [-1, true, 0, [3, null]],'Scale, one user, not completed' => [-1, false, 0, [3, null]],];}/*** Create a fake attempt for a specific user.** @param stdClass $activity activity instance record.* @param stdClass $user user record* @param int $rawscore score obtained* @param int $maxscore attempt max score* @param int $completion 1 for activity completed, 0 for not completed yet* @return stdClass the attempt record*/private function generate_fake_attempt(stdClass $activity, stdClass $user,int $rawscore, int $maxscore, int $completion = 1): stdClass {global $DB;$attempt = (object)['h5pactivityid' => $activity->id,'userid' => $user->id,'timecreated' => 10,'timemodified' => 20,'attempt' => 1,'rawscore' => $rawscore,'maxscore' => $maxscore,'duration' => 2,'completion' => $completion,'success' => 0,];$attempt->scaled = $attempt->rawscore / $attempt->maxscore;$attempt->id = $DB->insert_record('h5pactivity_attempts', $attempt);return $attempt;}}