Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401]

   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  /**
  18   * Unit tests for Accumulative grading strategy logic
  19   *
  20   * @package    workshopform_accumulative
  21   * @category   test
  22   * @copyright  2009 David Mudrak <david.mudrak@gmail.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace workshopform_accumulative;
  26  
  27  use workshop;
  28  use workshop_accumulative_strategy;
  29  
  30  defined('MOODLE_INTERNAL') || die();
  31  
  32  // Include the code to test
  33  global $CFG;
  34  require_once($CFG->dirroot . '/mod/workshop/locallib.php');
  35  require_once($CFG->dirroot . '/mod/workshop/form/accumulative/lib.php');
  36  
  37  /**
  38   * Unit tests for Accumulative grading strategy lib.php
  39   */
  40  class lib_test extends \advanced_testcase {
  41      /** workshop instance emulation */
  42      protected $workshop;
  43  
  44      /** @var testable_workshop_accumulative_strategy instance of the strategy logic class being tested */
  45      protected $strategy;
  46  
  47      /**
  48       * Setup testing environment
  49       */
  50      protected function setUp(): void {
  51          parent::setUp();
  52          $this->resetAfterTest();
  53          $this->setAdminUser();
  54          $course = $this->getDataGenerator()->create_course();
  55          $workshop = $this->getDataGenerator()->create_module('workshop', array('strategy' => 'accumulative', 'course' => $course));
  56          $cm = get_fast_modinfo($course)->instances['workshop'][$workshop->id];
  57          $this->workshop = new workshop($workshop, $cm, $course);
  58          $this->strategy = new testable_workshop_accumulative_strategy($this->workshop);
  59      }
  60  
  61      protected function tearDown(): void {
  62          $this->workshop = null;
  63          $this->strategy = null;
  64          parent::tearDown();
  65      }
  66  
  67      public function test_calculate_peer_grade_null_grade() {
  68          // fixture set-up
  69          $this->strategy->dimensions = array();
  70          $grades = array();
  71          // exercise SUT
  72          $suggested = $this->strategy->calculate_peer_grade($grades);
  73          // validate
  74          $this->assertNull($suggested);
  75      }
  76  
  77      public function test_calculate_peer_grade_one_numerical() {
  78          // fixture set-up
  79          $this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '1');
  80          $grades[] = (object)array('dimensionid' => 1003, 'grade' => '5.00000');
  81          // exercise SUT
  82          $suggested = $this->strategy->calculate_peer_grade($grades);
  83          // validate
  84          $this->assertEquals(grade_floatval(5/20 * 100), $suggested);
  85      }
  86  
  87      public function test_calculate_peer_grade_negative_weight() {
  88          // fixture set-up
  89          $this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '-1');
  90          $grades[] = (object)array('dimensionid' => 1003, 'grade' => '20');
  91          // exercise SUT
  92          $this->expectException(\coding_exception::class);
  93          $suggested = $this->strategy->calculate_peer_grade($grades);
  94      }
  95  
  96      public function test_calculate_peer_grade_one_numerical_weighted() {
  97          // fixture set-up
  98          $this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '3');
  99          $grades[] = (object)array('dimensionid' => '1003', 'grade' => '5');
 100          // exercise SUT
 101          $suggested = $this->strategy->calculate_peer_grade($grades);
 102          // validate
 103          $this->assertEquals(grade_floatval(5/20 * 100), $suggested);
 104      }
 105  
 106      public function test_calculate_peer_grade_three_numericals_same_weight() {
 107          // fixture set-up
 108          $this->strategy->dimensions[1003] = (object)array('grade' => '20', 'weight' => '2');
 109          $this->strategy->dimensions[1004] = (object)array('grade' => '100', 'weight' => '2');
 110          $this->strategy->dimensions[1005] = (object)array('grade' => '10', 'weight' => '2');
 111          $grades[] = (object)array('dimensionid' => 1003, 'grade' => '11.00000');
 112          $grades[] = (object)array('dimensionid' => 1004, 'grade' => '87.00000');
 113          $grades[] = (object)array('dimensionid' => 1005, 'grade' => '10.00000');
 114  
 115          // exercise SUT
 116          $suggested = $this->strategy->calculate_peer_grade($grades);
 117  
 118          // validate
 119          $this->assertEquals(grade_floatval((11/20 + 87/100 + 10/10)/3 * 100), $suggested);
 120      }
 121  
 122      public function test_calculate_peer_grade_three_numericals_different_weights() {
 123          // fixture set-up
 124          $this->strategy->dimensions[1003] = (object)array('grade' => '15', 'weight' => 3);
 125          $this->strategy->dimensions[1004] = (object)array('grade' => '80', 'weight' => 1);
 126          $this->strategy->dimensions[1005] = (object)array('grade' => '5', 'weight' => 2);
 127          $grades[] = (object)array('dimensionid' => 1003, 'grade' => '7.00000');
 128          $grades[] = (object)array('dimensionid' => 1004, 'grade' => '66.00000');
 129          $grades[] = (object)array('dimensionid' => 1005, 'grade' => '4.00000');
 130  
 131          // exercise SUT
 132          $suggested = $this->strategy->calculate_peer_grade($grades);
 133  
 134          // validate
 135          $this->assertEquals(grade_floatval((7/15*3 + 66/80*1 + 4/5*2)/6 * 100), $suggested);
 136      }
 137  
 138      public function test_calculate_peer_grade_one_scale_max() {
 139          $this->resetAfterTest(true);
 140  
 141          // fixture set-up
 142          $scale11 = $this->getDataGenerator()->create_scale(array('scale'=>'E,D,C,B,A', 'id'=>11));
 143          $this->strategy->dimensions[1008] = (object)array('grade' => (-$scale11->id), 'weight' => 1);
 144          $grades[] = (object)array('dimensionid' => 1008, 'grade' => '5.00000');
 145  
 146          // exercise SUT
 147          $suggested = $this->strategy->calculate_peer_grade($grades);
 148  
 149          // validate
 150          $this->assertEquals(100.00000, $suggested);
 151      }
 152  
 153      public function test_calculate_peer_grade_one_scale_min_with_scale_caching() {
 154          $this->resetAfterTest(true);
 155  
 156          // fixture set-up
 157          $scale11 = $this->getDataGenerator()->create_scale(array('scale'=>'E,D,C,B,A', 'id'=>11));
 158          $this->strategy->dimensions[1008] = (object)array('grade' => (-$scale11->id), 'weight' => 1);
 159          $grades[] = (object)array('dimensionid' => 1008, 'grade' => '1.00000');
 160  
 161          // exercise SUT
 162          $suggested = $this->strategy->calculate_peer_grade($grades);
 163  
 164          // validate
 165          $this->assertEquals(0.00000, $suggested);
 166      }
 167  
 168      public function test_calculate_peer_grade_two_scales_weighted() {
 169          $this->resetAfterTest(true);
 170          // fixture set-up
 171          $scale13 = $this->getDataGenerator()->create_scale(array('scale'=>'Poor,Good,Excellent', 'id'=>13));
 172          $scale17 = $this->getDataGenerator()->create_scale(array('scale'=>'-,*,**,***,****,*****,******', 'id'=>17));
 173          $this->strategy->dimensions[1012] = (object)array('grade' => (-$scale13->id), 'weight' => 2);
 174          $this->strategy->dimensions[1019] = (object)array('grade' => (-$scale17->id), 'weight' => 3);
 175          $grades[] = (object)array('dimensionid' => 1012, 'grade' => '2.00000'); // "Good"
 176          $grades[] = (object)array('dimensionid' => 1019, 'grade' => '5.00000'); // "****"
 177  
 178          // exercise SUT
 179          $suggested = $this->strategy->calculate_peer_grade($grades);
 180  
 181          // validate
 182          $this->assertEquals(grade_floatval((1/2*2 + 4/6*3)/5 * 100), $suggested);
 183      }
 184  
 185      public function test_calculate_peer_grade_scale_exception() {
 186          $this->resetAfterTest(true);
 187          // fixture set-up
 188          $scale13 = $this->getDataGenerator()->create_scale(array('scale'=>'Poor,Good,Excellent', 'id'=>13));
 189          $this->strategy->dimensions[1012] = (object)array('grade' => (-$scale13->id), 'weight' => 1);
 190          $grades[] = (object)array('dimensionid' => 1012, 'grade' => '4.00000'); // exceeds the number of scale items
 191  
 192          // Exercise SUT.
 193          $this->expectException(\coding_exception::class);
 194          $suggested = $this->strategy->calculate_peer_grade($grades);
 195      }
 196  }
 197  
 198  
 199  /**
 200   * Test subclass that makes all the protected methods we want to test public
 201   */
 202  class testable_workshop_accumulative_strategy extends workshop_accumulative_strategy {
 203  
 204      /** allows to set dimensions manually */
 205      public $dimensions = array();
 206  
 207      /**
 208       * This is where the calculation of suggested grade for submission is done
 209       */
 210      public function calculate_peer_grade(array $grades) {
 211          return parent::calculate_peer_grade($grades);
 212      }
 213  }