mirror of
https://github.com/moodle/moodle.git
synced 2025-04-15 05:25:08 +02:00
MDL-19931 Number of errors - grading strategy logic implemented
This commit is contained in:
parent
1dbbccb7a2
commit
4eae27fda8
@ -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);
|
||||
$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->mappings = array(
|
||||
1 => (object)array('grade' => 66.0),
|
||||
2 => (object)array('grade' => 33.0),
|
||||
3 => (object)array('grade' => 0.0),
|
||||
);
|
||||
|
||||
$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(1, $suggested);
|
||||
$this->assertEqual($suggested, 0.33);
|
||||
}
|
||||
|
||||
public function test_calculate_peer_grade_one_scale_min_with_scale_caching() {
|
||||
global $DB;
|
||||
|
||||
public function test_calculate_peer_grade_zero_weight() {
|
||||
// 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
|
||||
$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->mappings = array(
|
||||
1 => (object)array('grade' => 66.0),
|
||||
2 => (object)array('grade' => 33.0),
|
||||
3 => (object)array('grade' => 0.0),
|
||||
);
|
||||
|
||||
$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(0, $suggested);
|
||||
$this->assertEqual($suggested, 1.0);
|
||||
}
|
||||
|
||||
public function test_calculate_peer_grade_two_scales_weighted() {
|
||||
global $DB;
|
||||
|
||||
public function test_calculate_peer_grade_sum_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' => 3);
|
||||
|
||||
$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' => 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[] = (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' => 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((1/2*2 + 4/6*3)/5, $suggested);
|
||||
}
|
||||
|
||||
public function test_calculate_peer_grade_scale_exception() {
|
||||
global $DB;
|
||||
|
||||
// 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');
|
||||
|
||||
// excercise SUT
|
||||
$suggested = $this->strategy->calculate_peer_grade($grades);
|
||||
$this->assertEqual($suggested, 0.05);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user