2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Unit tests for grading evaluation method "best"
20 * @package workshopeval_best
22 * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 // Include the code to test
30 require_once($CFG->dirroot . '/mod/workshop/locallib.php');
31 require_once($CFG->dirroot . '/mod/workshop/eval/best/lib.php');
32 require_once($CFG->libdir . '/gradelib.php');
35 class workshopeval_best_evaluation_testcase extends basic_testcase {
37 /** workshop instance emulation */
40 /** instance of the grading evaluator being tested */
44 * Setup testing environment
46 protected function setUp() {
50 $course = new stdclass();
51 $context = new stdclass();
52 $workshop = (object)array('id' => 42, 'evaluation' => 'best');
53 $this->workshop = new workshop($workshop, $cm, $course, $context);
54 $this->evaluator = new testable_workshop_best_evaluation($this->workshop);
57 protected function tearDown() {
58 $this->workshop = null;
59 $this->evaluator = null;
63 public function test_normalize_grades() {
65 $assessments = array();
66 $assessments[1] = (object)array(
67 'dimgrades' => array(3 => 1.0000, 4 => 13.42300),
69 $assessments[3] = (object)array(
70 'dimgrades' => array(3 => 2.0000, 4 => 19.1000),
72 $assessments[7] = (object)array(
73 'dimgrades' => array(3 => 3.0000, 4 => 0.00000),
76 3 => (object)array('min' => 1, 'max' => 3),
77 4 => (object)array('min' => 0, 'max' => 20),
80 $norm = $this->evaluator->normalize_grades($assessments, $diminfo);
82 $this->assertEquals(gettype($norm), 'array');
83 // the following grades from a scale
84 $this->assertEquals($norm[1]->dimgrades[3], 0);
85 $this->assertEquals($norm[3]->dimgrades[3], 50);
86 $this->assertEquals($norm[7]->dimgrades[3], 100);
87 // the following grades from an interval 0 - 20
88 $this->assertEquals($norm[1]->dimgrades[4], grade_floatval(13.423 / 20 * 100));
89 $this->assertEquals($norm[3]->dimgrades[4], grade_floatval(19.1 / 20 * 100));
90 $this->assertEquals($norm[7]->dimgrades[4], 0);
93 public function test_normalize_grades_max_equals_min() {
95 $assessments = array();
96 $assessments[1] = (object)array(
97 'dimgrades' => array(3 => 100.0000),
100 3 => (object)array('min' => 100, 'max' => 100),
103 $norm = $this->evaluator->normalize_grades($assessments, $diminfo);
105 $this->assertEquals(gettype($norm), 'array');
106 $this->assertEquals($norm[1]->dimgrades[3], 100);
109 public function test_average_assessment_same_weights() {
111 $assessments = array();
112 $assessments[18] = (object)array(
114 'dimgrades' => array(1 => 50, 2 => 33.33333),
116 $assessments[16] = (object)array(
118 'dimgrades' => array(1 => 0, 2 => 66.66667),
121 $average = $this->evaluator->average_assessment($assessments);
123 $this->assertEquals(gettype($average->dimgrades), 'array');
124 $this->assertEquals(grade_floatval($average->dimgrades[1]), grade_floatval(25));
125 $this->assertEquals(grade_floatval($average->dimgrades[2]), grade_floatval(50));
128 public function test_average_assessment_different_weights() {
130 $assessments = array();
131 $assessments[11] = (object)array(
133 'dimgrades' => array(3 => 10.0, 4 => 13.4, 5 => 95.0),
135 $assessments[13] = (object)array(
137 'dimgrades' => array(3 => 11.0, 4 => 10.1, 5 => 92.0),
139 $assessments[17] = (object)array(
141 'dimgrades' => array(3 => 11.0, 4 => 8.1, 5 => 88.0),
144 $average = $this->evaluator->average_assessment($assessments);
146 $this->assertEquals(gettype($average->dimgrades), 'array');
147 $this->assertEquals(grade_floatval($average->dimgrades[3]), grade_floatval((10.0 + 11.0*3 + 11.0)/5));
148 $this->assertEquals(grade_floatval($average->dimgrades[4]), grade_floatval((13.4 + 10.1*3 + 8.1)/5));
149 $this->assertEquals(grade_floatval($average->dimgrades[5]), grade_floatval((95.0 + 92.0*3 + 88.0)/5));
152 public function test_average_assessment_noweight() {
154 $assessments = array();
155 $assessments[11] = (object)array(
157 'dimgrades' => array(3 => 10.0, 4 => 13.4, 5 => 95.0),
159 $assessments[17] = (object)array(
161 'dimgrades' => array(3 => 11.0, 4 => 8.1, 5 => 88.0),
164 $average = $this->evaluator->average_assessment($assessments);
166 $this->assertNull($average);
169 public function test_weighted_variance() {
171 $assessments[11] = (object)array(
173 'dimgrades' => array(3 => 11, 4 => 2),
175 $assessments[13] = (object)array(
177 'dimgrades' => array(3 => 11, 4 => 4),
179 $assessments[17] = (object)array(
181 'dimgrades' => array(3 => 11, 4 => 5),
183 $assessments[20] = (object)array(
185 'dimgrades' => array(3 => 11, 4 => 7),
187 $assessments[25] = (object)array(
189 'dimgrades' => array(3 => 11, 4 => 9),
192 $variance = $this->evaluator->weighted_variance($assessments);
194 // dimension [3] have all the grades equal to 11
195 $this->assertEquals($variance[3], 0);
196 // dimension [4] represents data 2, 4, 4, 4, 5, 5, 7, 9 having stdev=2 (stdev is sqrt of variance)
197 $this->assertEquals($variance[4], 4);
200 public function test_assessments_distance_zero() {
203 3 => (object)array('weight' => 1, 'min' => 0, 'max' => 100, 'variance' => 12.34567),
204 4 => (object)array('weight' => 1, 'min' => 1, 'max' => 5, 'variance' => 98.76543),
206 $assessment1 = (object)array('dimgrades' => array(3 => 15, 4 => 2));
207 $assessment2 = (object)array('dimgrades' => array(3 => 15, 4 => 2));
208 $settings = (object)array('comparison' => 5);
209 // exercise SUT and validate
210 $this->assertEquals($this->evaluator->assessments_distance($assessment1, $assessment2, $diminfo, $settings), 0);
213 public function test_assessments_distance_equals() {
217 3 => (object)array('weight' => 1, 'min' => 0, 'max' => 100, 'variance' => 12.34567),
218 4 => (object)array('weight' => 1, 'min' => 0, 'max' => 100, 'variance' => 12.34567),
220 $assessment1 = (object)array('dimgrades' => array(3 => 25, 4 => 4));
221 $assessment2 = (object)array('dimgrades' => array(3 => 75, 4 => 2));
222 $referential = (object)array('dimgrades' => array(3 => 50, 4 => 3));
223 $settings = (object)array('comparison' => 5);
224 // exercise SUT and validate
225 $this->assertEquals($this->evaluator->assessments_distance($assessment1, $referential, $diminfo, $settings),
226 $this->evaluator->assessments_distance($assessment2, $referential, $diminfo, $settings));
230 1 => (object)array('min' => 0, 'max' => 2, 'weight' => 1, 'variance' => 625),
231 2 => (object)array('min' => 0, 'max' => 3, 'weight' => 1, 'variance' => 277.7778888889),
233 $assessment1 = (object)array('dimgrades' => array(1 => 0, 2 => 66.66667));
234 $assessment2 = (object)array('dimgrades' => array(1 => 50, 2 => 33.33333));
235 $referential = (object)array('dimgrades' => array(1 => 25, 2 => 50));
236 $settings = (object)array('comparison' => 9);
237 // exercise SUT and validate
238 $this->assertEquals($this->evaluator->assessments_distance($assessment1, $referential, $diminfo, $settings),
239 $this->evaluator->assessments_distance($assessment2, $referential, $diminfo, $settings));
243 public function test_assessments_distance_zero_variance() {
244 // Fixture set-up: an assessment form of the strategy "Number of errors",
245 // three assertions, same weight.
247 1 => (object)array('min' => 0, 'max' => 1, 'weight' => 1),
248 2 => (object)array('min' => 0, 'max' => 1, 'weight' => 1),
249 3 => (object)array('min' => 0, 'max' => 1, 'weight' => 1),
252 // Simulate structure returned by {@link workshop_best_evaluation::prepare_data_from_recordset()}
253 $assessments = array(
254 // The first assessment has weight 0 and the assessment was No, No, No.
256 'assessmentid' => 10,
259 'gradinggrade' => null,
260 'submissionid' => 99,
261 'dimgrades' => array(
267 // The second assessment has weight 1 and assessments was Yes, Yes, Yes.
269 'assessmentid' => 20,
272 'gradinggrade' => null,
273 'submissionid' => 99,
274 'dimgrades' => array(
280 // The third assessment has weight 1 and assessments was Yes, Yes, Yes too.
282 'assessmentid' => 30,
285 'gradinggrade' => null,
286 'submissionid' => 99,
287 'dimgrades' => array(
295 // Process assessments in the same way as in the {@link workshop_best_evaluation::process_assessments()}
296 $assessments = $this->evaluator->normalize_grades($assessments, $diminfo);
297 $average = $this->evaluator->average_assessment($assessments);
298 $variances = $this->evaluator->weighted_variance($assessments);
299 foreach ($variances as $dimid => $variance) {
300 $diminfo[$dimid]->variance = $variance;
303 // Simulate the chosen comparison of assessments "fair" (does not really matter here but we need something).
304 $settings = (object)array('comparison' => 5);
306 // Exercise SUT: for every assessment, calculate its distance from the average one.
307 $distances = array();
308 foreach ($assessments as $asid => $assessment) {
309 $distances[$asid] = $this->evaluator->assessments_distance($assessment, $average, $diminfo, $settings);
312 // Validate: the first assessment is far far away from the average one ...
313 $this->assertTrue($distances[10] > 0);
314 // ... while the two others were both picked as the referential ones.
315 $this->assertTrue($distances[20] == 0);
316 $this->assertTrue($distances[30] == 0);
322 * Test subclass that makes all the protected methods we want to test public.
324 class testable_workshop_best_evaluation extends workshop_best_evaluation {
326 public function normalize_grades(array $assessments, array $diminfo) {
327 return parent::normalize_grades($assessments, $diminfo);
329 public function average_assessment(array $assessments) {
330 return parent::average_assessment($assessments);
332 public function weighted_variance(array $assessments) {
333 return parent::weighted_variance($assessments);
335 public function assessments_distance(stdclass $assessment, stdclass $referential, array $diminfo, stdclass $settings) {
336 return parent::assessments_distance($assessment, $referential, $diminfo, $settings);