]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-19931 Number of errors - grading strategy logic implemented
authorDavid Mudrak <david.mudrak@gmail.com>
Mon, 4 Jan 2010 17:58:26 +0000 (17:58 +0000)
committerDavid Mudrak <david.mudrak@gmail.com>
Mon, 4 Jan 2010 17:58:26 +0000 (17:58 +0000)
mod/workshop/grading/noerrors/simpletest/teststrategy.php
mod/workshop/grading/noerrors/strategy.php

index 3dfd168c18c1062ddf142a3b4ae5db02e8d931e9..eba908076471a84df2e8a40f00304856e4a48489 100644 (file)
@@ -39,6 +39,9 @@ class testable_workshop_noerrors_strategy extends workshop_noerrors_strategy {
     /** allows to set dimensions manually */
     public $dimensions = array();
 
+    /** allow to set mappings manually */
+    public $mappings = array();
+
     /**
      * This is where the calculation of suggested grade for submission is done
      */
@@ -83,7 +86,8 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
 
     public function test_calculate_peer_grade_null_grade() {
         // fixture set-up
-        $this->dimensions = array();
+        $this->strategy->dimensions   = array();
+        $this->strategy->mappings     = array();
         $grades = array();
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
@@ -91,138 +95,167 @@ class workshop_noerrors_strategy_test extends UnitTestCase {
         $this->assertNull($suggested);
     }
 
-    public function test_calculate_peer_grade_one_numerical() {
+    public function test_calculate_peer_grade_no_error() {
         // fixture set-up
-        $this->strategy->dimensions[1003] = (object)array('grade' => 20, 'weight' => 1);
-        $grades[] = (object)array('dimensionid' => 1003, 'grade' => 5);
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 1);
+        $this->strategy->dimensions[111] = (object)array('weight' => 1);
+        $this->strategy->mappings        = array();
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 1);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 1);
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
         // validate
-        $this->assertEqual(5/20, $suggested);
+        $this->assertEqual($suggested, 1.0);
     }
 
-    public function test_calculate_peer_grade_negative_weight() {
+    public function test_calculate_peer_grade_one_error() {
         // fixture set-up
-        $this->strategy->dimensions[1003] = (object)array('grade' => 20, 'weight' => -1);
-        $grades[] = (object)array('dimensionid' => 1003, 'grade' => 20);
-        $this->expectException('coding_exception');
-        // excercise SUT
-        $suggested = $this->strategy->calculate_peer_grade($grades);
-    }
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 1);
+        $this->strategy->dimensions[111] = (object)array('weight' => 1);
+
+        $this->strategy->mappings        = array(
+                                                1 => (object)array('grade' => 80.0),
+                                                2 => (object)array('grade' => 60.0),
+                                            );
+
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 1);
 
-    public function test_calculate_peer_grade_one_numerical_weighted() {
-        // fixture set-up
-        $this->strategy->dimensions[1003] = (object)array('grade' => 20, 'weight' => 3);
-        $grades[] = (object)array('dimensionid' => 1003, 'grade' => 5);
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
         // validate
-        $this->assertEqual(5/20, $suggested);
+        $this->assertEqual($suggested, 0.8);
     }
 
-    public function test_calculate_peer_grade_three_numericals_same_weight() {
+    public function test_calculate_peer_grade_three_errors_same_weight_a() {
         // fixture set-up
-        $this->strategy->dimensions[1003] = (object)array('grade' =>20, 'weight' => 2);
-        $this->strategy->dimensions[1004] = (object)array('grade' =>100, 'weight' => 2);
-        $this->strategy->dimensions[1005] = (object)array('grade' =>10, 'weight' => 2);
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 1);
+        $this->strategy->dimensions[111] = (object)array('weight' => 1);
 
-        $grades[] = (object)array('dimensionid' => 1003, 'grade' => 11);
-        $grades[] = (object)array('dimensionid' => 1004, 'grade' => 87);
-        $grades[] = (object)array('dimensionid' => 1005, 'grade' => 10);
+        $this->strategy->mappings        = array(
+                                                1 => (object)array('grade' => 80.0),
+                                                2 => (object)array('grade' => 60.0),
+                                                3 => (object)array('grade' => 10.0),
+                                            );
+
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
 
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
-
         // validate
-        $this->assertEqual((11/20 + 87/100 + 10/10)/3, $suggested);
+        $this->assertEqual($suggested, 0.1);
     }
 
-    public function test_calculate_peer_grade_three_numericals_different_weights() {
+    public function test_calculate_peer_grade_three_errors_same_weight_b() {
         // fixture set-up
-        $this->strategy->dimensions[1003] = (object)array('grade' =>15, 'weight' => 3);
-        $this->strategy->dimensions[1004] = (object)array('grade' =>80, 'weight' => 1);
-        $this->strategy->dimensions[1005] = (object)array('grade' =>5, 'weight' => 2);
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 1);
+        $this->strategy->dimensions[111] = (object)array('weight' => 1);
 
-        $grades[] = (object)array('dimensionid' => 1003, 'grade' => 7);
-        $grades[] = (object)array('dimensionid' => 1004, 'grade' => 66);
-        $grades[] = (object)array('dimensionid' => 1005, 'grade' => 4);
+        $this->strategy->mappings        = array(
+                                                1 => (object)array('grade' => 80.0),
+                                                2 => (object)array('grade' => 60.0),
+                                                3 => (object)array('grade' => 0.0),
+                                            );
+
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
 
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
-
         // validate
-        $this->assertEqual((7/15*3 + 66/80*1 + 4/5*2)/6, $suggested);
+        $this->assertEqual($suggested, 0);
     }
 
-    public function test_calculate_peer_grade_one_scale_max() {
-        global $DB;
-
+    public function test_calculate_peer_grade_one_error_weighted() {
         // fixture set-up
-        $mockscale = 'E,D,C,B,A';
-        $this->strategy->dimensions[1008] = (object)array('grade' => -10, 'weight' => 1);
-        $grades[] = (object)array('dimensionid' => 1008, 'grade' => 5);
-        $DB->expectOnce('get_field', array("scales", "scale", array("id" => 10), MUST_EXIST));
-        $DB->setReturnValue('get_field', $mockscale);
-
-        // excercise SUT
-        $suggested = $this->strategy->calculate_peer_grade($grades);
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 2);
+        $this->strategy->dimensions[111] = (object)array('weight' => 0);
 
-        // validate
-        $this->assertEqual(1, $suggested);
-    }
-
-    public function test_calculate_peer_grade_one_scale_min_with_scale_caching() {
-        global $DB;
+        $this->strategy->mappings        = array(
+                                                1 => (object)array('grade' => 66.0),
+                                                2 => (object)array('grade' => 33.0),
+                                                3 => (object)array('grade' => 0.0),
+                                            );
 
-        // fixture set-up
-        $this->strategy->dimensions[1008] = (object)array('grade' => -10, 'weight' => 1);
-        $grades[] = (object)array('dimensionid' => 1008, 'grade' => 1);
-        $DB->expectNever('get_field', array("scales", "scale", array("id" => 10), MUST_EXIST)); // cached
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 1);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
 
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
-
         // validate
-        $this->assertEqual(0, $suggested);
+        $this->assertEqual($suggested, 0.33);
     }
 
-    public function test_calculate_peer_grade_two_scales_weighted() {
-        global $DB;
-
+    public function test_calculate_peer_grade_zero_weight() {
         // fixture set-up
-        $mockscale13 = 'Poor,Good,Excellent';
-        $mockscale17 = '-,*,**,***,****,*****,******';
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 2);
+        $this->strategy->dimensions[111] = (object)array('weight' => 0);
 
-        $this->strategy->dimensions[1012] = (object)array('grade' => -13, 'weight' => 2);
-        $this->strategy->dimensions[1019] = (object)array('grade' => -17, 'weight' => 3);
+        $this->strategy->mappings        = array(
+                                                1 => (object)array('grade' => 66.0),
+                                                2 => (object)array('grade' => 33.0),
+                                                3 => (object)array('grade' => 0.0),
+                                            );
 
-        $grades[] = (object)array('dimensionid' => 1012, 'grade' => 2); // "Good"
-        $grades[] = (object)array('dimensionid' => 1019, 'grade' => 5); // "****"
-
-        $DB->expectAt(0, 'get_field', array("scales", "scale", array("id" => 13), MUST_EXIST));
-        $DB->setReturnValueAt(0, 'get_field', $mockscale13);
-
-        $DB->expectAt(1, 'get_field', array("scales", "scale", array("id" => 17), MUST_EXIST));
-        $DB->setReturnValueAt(1, 'get_field', $mockscale17);
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 1);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 1);
 
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
-
         // validate
-        $this->assertEqual((1/2*2 + 4/6*3)/5, $suggested);
+        $this->assertEqual($suggested, 1.0);
     }
 
-    public function test_calculate_peer_grade_scale_exception() {
-        global $DB;
-
+    public function test_calculate_peer_grade_sum_weight() {
         // fixture set-up
-        $mockscale13 = 'Poor,Good,Excellent';
-        $this->strategy->dimensions[1012] = (object)array('grade' => -13, 'weight' => 1);
-        $DB->expectNever('get_field', array("scales", "scale", array("id" => 13), MUST_EXIST)); // cached
-        $grades[] = (object)array('dimensionid' => 1012, 'grade' => 4); // exceeds the number of scale items
-        $this->expectException('coding_exception');
+        $this->strategy->dimensions      = array();
+        $this->strategy->dimensions[108] = (object)array('weight' => 1);
+        $this->strategy->dimensions[109] = (object)array('weight' => 2);
+        $this->strategy->dimensions[111] = (object)array('weight' => 3);
+
+        $this->strategy->mappings        = array(
+                                                1 => (object)array('grade' => 90.0),
+                                                2 => (object)array('grade' => 80.0),
+                                                3 => (object)array('grade' => 70.0),
+                                                4 => (object)array('grade' => 60.0),
+                                                5 => (object)array('grade' => 30.0),
+                                                6 => (object)array('grade' => 5.0),
+                                                7 => (object)array('grade' => 0.0),
+                                            );
+
+        $grades = array();
+        $grades[] = (object)array('dimensionid' => 108, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 111, 'grade' => 0);
+        $grades[] = (object)array('dimensionid' => 109, 'grade' => 0);
 
         // excercise SUT
         $suggested = $this->strategy->calculate_peer_grade($grades);
+        // validate
+        $this->assertEqual($suggested, 0.05);
     }
 }
index e5b44802686cdc3486f518b1b367fb31c92279d7..e92b2c48f84feb531d4991f7a57d2dd7bffb6a16 100644 (file)
@@ -446,17 +446,54 @@ class workshop_noerrors_strategy implements workshop_strategy {
      * Calculates the aggregated grade given by the reviewer
      *
      * @param array $grades Grade records as returned by {@link get_current_assessment_data}
-     * @uses $this->mappings
      * @return float|null   Raw grade (0 to 1) for submission as suggested by the peer
      */
     protected function calculate_peer_grade(array $grades) {
-
         if (empty($grades)) {
             return null;
         }
-        $sumgrades  = 0;
-        $sumweights = 0;
-        return 1;
+        $sumerrors  = 0;    // sum of the weighted errors (ie the negative responses)
+        foreach ($grades as $grade) {
+            if (empty($grade->grade)) {
+                // negative reviewer's response
+                $sumerrors += $this->dimensions[$grade->dimensionid]->weight;
+            }
+        }
+        return $this->errors_to_grade($sumerrors);
     }
 
+    /**
+     * Returns a grade 0..1 for the given number of errors
+     *
+     * This is where we use the mapping table defined by the teacher. If a grade for the given
+     * number of errors (negative assertions) is not defined, the most recently defined one is used.
+     * Example of the defined mapping:
+     * Number of errors | Grade
+     *                0 | 100%  (always)
+     *                1 | -     (not defined)
+     *                2 | 80%
+     *                3 | 60%
+     *                4 | -
+     *                5 | 30%
+     *                6 | 0%
+     * With this mapping, one error is mapped to 100% grade and 4 errors is mapped to 60%.
+     *
+     * @param mixed $noerrors Number of errors
+     * @return float          Raw grade (0 to 1) for the given number of negative assertions
+     */
+    protected function errors_to_grade($noerrors) {
+        $grade = 100;
+        for ($i = 1; $i <= $noerrors; $i++) {
+            if (isset($this->mappings[$i])) {
+                $grade = $this->mappings[$i]->grade;
+            }
+        }
+        if ($grade > 100) {
+            $grade = 100;
+        }
+        if ($grade < 0) {
+            $grade = 0;
+        }
+        return $grade/100;
+    }
 }