Merge branch 'wip_MDL-40077' of https://github.com/jamiepratt/moodle
This commit is contained in:
@@ -122,21 +122,7 @@ class quiz_statistics_report extends quiz_default_report {
|
||||
$filename = quiz_report_download_filename($report, $courseshortname, $quiz->name);
|
||||
$this->table->is_downloading($download, $filename,
|
||||
get_string('quizstructureanalysis', 'quiz_statistics'));
|
||||
|
||||
// Load the questions.
|
||||
$questions = quiz_report_get_significant_questions($quiz);
|
||||
$questionids = array();
|
||||
foreach ($questions as $question) {
|
||||
$questionids[] = $question->id;
|
||||
}
|
||||
$fullquestions = question_load_questions($questionids);
|
||||
foreach ($questions as $qno => $question) {
|
||||
$q = $fullquestions[$question->id];
|
||||
$q->maxmark = $question->maxmark;
|
||||
$q->slot = $qno;
|
||||
$q->number = $question->number;
|
||||
$questions[$qno] = $q;
|
||||
}
|
||||
$questions = $this->load_and_initialise_questions_for_calculations($quiz);
|
||||
|
||||
// Get the data to be displayed.
|
||||
list($quizstats, $questions, $subquestions, $s) =
|
||||
@@ -607,7 +593,7 @@ class quiz_statistics_report extends quiz_default_report {
|
||||
/**
|
||||
* Compute the quiz statistics.
|
||||
*
|
||||
* @param object $quizid the quiz id.
|
||||
* @param int $quizid the quiz id.
|
||||
* @param int $currentgroup the current group. 0 for none.
|
||||
* @param bool $nostudentsingroup true if there a no students.
|
||||
* @param bool $useallattempts use all attempts, or just first attempts.
|
||||
@@ -1057,6 +1043,28 @@ class quiz_statistics_report extends quiz_default_report {
|
||||
return get_string('firstattempts', 'quiz_statistics');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $quiz the quiz.
|
||||
* @return array of questions for this quiz.
|
||||
*/
|
||||
public function load_and_initialise_questions_for_calculations($quiz) {
|
||||
// Load the questions.
|
||||
$questions = quiz_report_get_significant_questions($quiz);
|
||||
$questionids = array();
|
||||
foreach ($questions as $question) {
|
||||
$questionids[] = $question->id;
|
||||
}
|
||||
$fullquestions = question_load_questions($questionids);
|
||||
foreach ($questions as $qno => $question) {
|
||||
$q = $fullquestions[$question->id];
|
||||
$q->maxmark = $question->maxmark;
|
||||
$q->slot = $qno;
|
||||
$q->number = $question->number;
|
||||
$questions[$qno] = $q;
|
||||
}
|
||||
return $questions;
|
||||
}
|
||||
}
|
||||
|
||||
function quiz_statistics_attempts_sql($quizid, $currentgroup, $groupstudents,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
slot,facility,sd,effectiveweight,covariance,markvariance,othermarkvariance,discriminationindex,covariancemax,discriminativeefficiency
|
||||
1,0.704,0.4513682901,21.2922742344,-0.022555556,0.2037333333,0.5002777794,-7.0650767526,0.2385555565,-9.4550536967
|
||||
2,0.48,0.5099019514,18.8979800309,-0.1172777785,0.26,0.6334555578,-28.8982125772,0.318833334,-36.7834118938
|
||||
3,0.973333332,0.13333334,4.443012573,-0.0098888894,0.0177777796,0.6609,-9.1230674268,0.045666669,-21.6545012165
|
||||
4,0.68,0.4760952286,18.9347251357,-0.0833888893,0.2266666667,0.5990111128,-22.6306444113,0.2652222232,-31.4411395613
|
||||
5,0.52,0.3055050463,11.1450138688,-0.0436944444,0.0933333333,0.6529555563,-17.6997047674,0.2063055556,-21.1794802584
|
||||
6,0.64,0.4898979486,9.8081339177,-0.2015555547,0.24,0.8220111101,-45.3785178421,0.3539999995,-56.9365974439
|
||||
7,0.62,0.331662479,15.4788602394,-0.0142499998,0.11,0.5774000005,-5.6543166602,0.2190833335,-6.5043742058
|
||||
|
@@ -0,0 +1,10 @@
|
||||
slot,type,which,cat,mark
|
||||
1,random,,rand,1
|
||||
,shortanswer,,rand,1
|
||||
,numerical,,rand,1
|
||||
2,calculatedsimple,sumwithvariants,maincat,1
|
||||
3,match,,maincat,1
|
||||
4,truefalse,,maincat,1
|
||||
5,multichoice,two_of_four,maincat,1
|
||||
6,multichoice,one_of_four,maincat,1
|
||||
7,multianswer,,maincat,1
|
||||
|
@@ -0,0 +1,26 @@
|
||||
quizattempt,slots.1.mark,slots.2.mark,slots.3.mark,slots.4.mark,slots.5.mark,slots.6.mark,slots.7.mark,summarks
|
||||
1,1,1,1,1,1,0,1,6
|
||||
2,1,1,1,1,0.5,1,0,5.5
|
||||
3,1,1,1,1,0.5,0,1,5.5
|
||||
4,0,0,1,1,1,0,0,3
|
||||
5,1,0,1,0,0,1,0.5,3.5
|
||||
6,1,1,1,1,0.5,0,0.5,5
|
||||
7,0,1,1,1,0.5,1,0.5,5
|
||||
8,1,1,1,0,0.5,1,0.5,5
|
||||
9,1,0,1,1,1,1,1,6
|
||||
10,0,1,1,0,0.5,1,0.5,4
|
||||
11,0.8,0,1,1,0.5,1,0.5,4.8
|
||||
12,1,1,1,0,0.5,1,1,5.5
|
||||
13,1,0,1,1,0.5,1,0.5,5
|
||||
14,1,0,1,1,1,0,0.5,4.5
|
||||
15,0,0,1,1,0,1,1,4
|
||||
16,1,0,1,0,0.5,1,1,4.5
|
||||
17,0.8,0,1,1,0.5,0,1,4.3
|
||||
18,1,0,1,1,0,1,0.5,4.5
|
||||
19,1,0,1,1,0.5,0,0.5,4
|
||||
20,0,1,1,0,0.5,1,0,3.5
|
||||
21,1,1,0.3333333,1,0.5,0,0.5,4.33333
|
||||
22,1,1,1,0,0.5,0,0.5,4
|
||||
23,1,1,1,1,0,1,0.5,5.5
|
||||
24,0,0,1,0,0.5,1,1,3.5
|
||||
25,0,0,1,1,1,1,1,5
|
||||
|
@@ -0,0 +1,26 @@
|
||||
quizattempt,firstname,lastname,randqs.1,responses.1.answer,variants.2,responses.2.answer,responses.3.0,responses.3.1,responses.3.2,responses.4.answer,responses.5.0,responses.5.1,responses.5.2,responses.5.3,responses.6.answer,responses.7.1.answer,responses.7.2.answer
|
||||
1,John,Jones,numerical,3.14,1,9.9,amphibian,mammal,amphibian,1,1,0,1,0,1,Owl,2
|
||||
2,John,Smith,shortanswer,frog,1,9.9,amphibian,mammal,amphibian,1,0,1,1,0,0,Dog,0
|
||||
3,John,Vicars,numerical,3.14,6,9.4,amphibian,mammal,amphibian,1,0,0,1,1,1,Owl,2
|
||||
4,John,Pacino,shortanswer,butterfly,6,-0.1,amphibian,mammal,amphibian,1,1,0,1,0,3,Dog,0
|
||||
5,John,Deniro,numerical,3.14,4,0,amphibian,mammal,amphibian,0,0,1,0,1,0,Dog,2
|
||||
6,John,Banks,numerical,3.14,1,9.9,amphibian,mammal,amphibian,1,1,0,0,1,1,Owl,1
|
||||
7,John,Asimov,numerical,3.142,7,9.1,amphibian,mammal,amphibian,1,0,0,1,1,0,Owl,1
|
||||
8,John,Chomsky,numerical,3.14,4,19.4,amphibian,mammal,amphibian,0,0,0,1,1,0,Owl,1
|
||||
9,John,Yamaguchi,shortanswer,frog,1,-0.7,amphibian,mammal,amphibian,1,1,0,1,0,0,Owl,2
|
||||
10,John,Robbins,numerical,3.1,5,14.2,amphibian,mammal,amphibian,0,0,1,1,0,0,Owl,0
|
||||
11,Joe,Jones,shortanswer,toad,6,-0.2,amphibian,mammal,amphibian,1,1,1,0,0,0,Owl,0
|
||||
12,Joe,Smith,shortanswer,frog,8,5.7,amphibian,mammal,amphibian,0,0,0,1,1,0,Owl,2
|
||||
13,Joe,Vicars,numerical,3.14,8,-0.2,amphibian,mammal,amphibian,1,1,0,0,1,0,wfz9p,2
|
||||
14,Joe,Pacino,shortanswer,frog,1,-0.2,amphibian,mammal,amphibian,1,1,0,1,0,1,Owl,0
|
||||
15,Joe,Deniro,numerical,3.1,7,-0.9,amphibian,mammal,amphibian,1,0,1,0,1,0,Owl,2
|
||||
16,Joe,Banks,shortanswer,frog,10,-0.7,amphibian,mammal,amphibian,0,1,0,0,1,0,Owl,2
|
||||
17,Joe,Asimov,shortanswer,toad,4,-0.4,amphibian,mammal,amphibian,1,0,1,1,0,2,Owl,2
|
||||
18,Joe,Chomsky,shortanswer,frog,6,-1,amphibian,mammal,amphibian,1,0,1,0,1,0,Pussy-cat,2
|
||||
19,Joe,Yamaguchi,numerical,3.14,8,-0.5,amphibian,mammal,amphibian,1,1,1,0,0,1,Owl,0
|
||||
20,Joe,Robbins,shortanswer,butterfly,4,19.4,amphibian,mammal,amphibian,0,0,1,1,0,0,"Wiggly worm",0
|
||||
21,Roberto,Jones,shortanswer,frog,8,5.7,amphibian,amphibian,mammal,1,0,1,1,0,2,RjUpn,2
|
||||
22,Roberto,Smith,shortanswer,frog,5,14.2,amphibian,mammal,amphibian,0,1,0,0,1,1,Dog,2
|
||||
23,Roberto,Vicars,shortanswer,frog,5,14.2,amphibian,mammal,amphibian,1,0,1,0,1,0,"Wiggly worm",2
|
||||
24,Roberto,Pacino,numerical,3.1,1,-1,amphibian,mammal,amphibian,0,1,1,0,0,0,Owl,2
|
||||
25,Roberto,Deniro,numerical,3.1,8,-0.1,amphibian,mammal,amphibian,1,1,0,1,0,0,Owl,2
|
||||
|
@@ -0,0 +1,142 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Quiz attempt walk through using data from csv file.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category phpunit
|
||||
* @copyright 2013 The Open University
|
||||
* @author Jamie Pratt <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/quiz/tests/attempt_walkthrough_from_csv_test.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/report/default.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
|
||||
/**
|
||||
* Test helper subclass of quiz_statistics_report
|
||||
*
|
||||
* @copyright 2013 The Open University
|
||||
* @author Jamie Pratt <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class testable_quiz_statistics_report extends quiz_statistics_report {
|
||||
|
||||
public function get_stats($quiz, $useallattempts = true,
|
||||
$currentgroup = 0, $groupstudents = array(), $nostudentsingroup = false) {
|
||||
$this->clear_cached_data($quiz->id, $currentgroup, $useallattempts);
|
||||
$questions = $this->load_and_initialise_questions_for_calculations($quiz);
|
||||
return $this->get_quiz_and_questions_stats($quiz, $currentgroup, $nostudentsingroup,
|
||||
$useallattempts, $groupstudents, $questions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quiz attempt walk through using data from csv file.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category phpunit
|
||||
* @copyright 2013 The Open University
|
||||
* @author Jamie Pratt <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_report_statistics_from_steps extends mod_quiz_attempt_walkthrough_from_csv_testcase {
|
||||
|
||||
/**
|
||||
* @var quiz_statistics_report object to do stats calculations.
|
||||
*/
|
||||
protected $report;
|
||||
|
||||
protected function get_full_path_of_csv_file($setname, $test) {
|
||||
// Overridden here so that __DIR__ points to the path of this file.
|
||||
return __DIR__."/fixtures/{$setname}{$test}.csv";
|
||||
}
|
||||
|
||||
protected $files = array('questions', 'steps', 'results', 'qstats');
|
||||
|
||||
/**
|
||||
* Create a quiz add questions to it, walk through quiz attempts and then check results.
|
||||
*
|
||||
* @param PHPUnit_Extensions_Database_DataSet_ITable[] of data read from csv file "questionsXX.csv",
|
||||
* "stepsXX.csv" and "resultsXX.csv".
|
||||
* @dataProvider get_data_for_walkthrough
|
||||
*/
|
||||
public function test_walkthrough_from_csv($csvdata) {
|
||||
|
||||
// CSV data files for these tests were generated using :
|
||||
// https://github.com/jamiepratt/moodle-quiz-tools/tree/master/responsegenerator
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
question_bank::get_qtype('random')->clear_caches_before_testing();
|
||||
|
||||
$this->create_quiz($csvdata['questions']);
|
||||
|
||||
$attemptids = $this->walkthrough_attempts($csvdata['steps']);
|
||||
|
||||
$this->check_attempts_results($csvdata['results'], $attemptids);
|
||||
|
||||
$this->report = new testable_quiz_statistics_report();
|
||||
list($quizstats, $questions, $subquestions, $s) = $this->report->get_stats($this->quiz);
|
||||
|
||||
// These quiz stats and the question stats found in qstats00.csv were calculated independently in spreadsheet which is
|
||||
// available in open document or excel format here :
|
||||
// https://github.com/jamiepratt/moodle-quiz-tools/tree/master/statsspreadsheet
|
||||
$quizstatsexpected = array(
|
||||
'median' => 4.5,
|
||||
'firstattemptsavg' => 4.617333332,
|
||||
'allattemptsavg' => 4.617333332,
|
||||
'firstattemptscount' => 25,
|
||||
'allattemptscount' => 25,
|
||||
'standarddeviation' => 0.8117265554,
|
||||
'skewness' => -0.092502502,
|
||||
'kurtosis' => -0.7073968557,
|
||||
'cic' => -87.2230935542,
|
||||
'errorratio' => 136.8294900795,
|
||||
'standarderror' => 1.1106813066
|
||||
);
|
||||
|
||||
foreach ($quizstatsexpected as $statname => $statvalue) {
|
||||
$this->assertEquals($statvalue, $quizstats->$statname, $quizstats->$statname, abs($statvalue) * 1e-5);
|
||||
}
|
||||
|
||||
for ($rowno = 0; $rowno < $csvdata['qstats']->getRowCount(); $rowno++) {
|
||||
$slotqstats = $csvdata['qstats']->getRow($rowno);
|
||||
foreach ($slotqstats as $statname => $slotqstat) {
|
||||
if ($statname !== 'slot') {
|
||||
switch ($statname) {
|
||||
case 'covariance' :
|
||||
case 'discriminationindex' :
|
||||
case 'discriminativeefficiency' :
|
||||
case 'effectiveweight' :
|
||||
$precision = 1e-5;
|
||||
break;
|
||||
default :
|
||||
$precision = 1e-6;
|
||||
}
|
||||
$slot = $slotqstats['slot'];
|
||||
$delta = abs($slotqstat) * $precision;
|
||||
$actual = $questions[$slot]->_stats->{$statname};
|
||||
$this->assertEquals(floatval($slotqstat), $actual, "$statname for slot $slot", $delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,8 @@ class mod_quiz_attempt_walkthrough_from_csv_testcase extends advanced_testcase {
|
||||
*/
|
||||
protected $tests = array('00');
|
||||
|
||||
protected $files = array('questions', 'steps', 'results');
|
||||
|
||||
/**
|
||||
* @var stdClass the quiz record we create.
|
||||
*/
|
||||
@@ -123,17 +125,6 @@ class mod_quiz_attempt_walkthrough_from_csv_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
public function get_data_for_walkthrough() {
|
||||
$dataset = array();
|
||||
foreach ($this->tests as $test) {
|
||||
$qs = $this->load_csv_data_file('questions', $test);
|
||||
$steps = $this->load_csv_data_file('steps', $test);
|
||||
$results = $this->load_csv_data_file('results', $test);
|
||||
$dataset[] = array($qs, $steps, $results);
|
||||
}
|
||||
return $dataset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full path of CSV file.
|
||||
*
|
||||
@@ -183,28 +174,59 @@ class mod_quiz_attempt_walkthrough_from_csv_testcase extends advanced_testcase {
|
||||
return $parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider method for test_walkthrough_from_csv. Called by PHPUnit.
|
||||
*
|
||||
* @return array One array element for each run of the test. Each element contains an array with the one param for
|
||||
* test_walkthrough_from_csv.
|
||||
*/
|
||||
public function get_data_for_walkthrough() {
|
||||
$datasets = array();
|
||||
foreach ($this->tests as $test) {
|
||||
$dataset = array();
|
||||
foreach ($this->files as $file) {
|
||||
$dataset[$file] = $this->load_csv_data_file($file, $test);
|
||||
}
|
||||
$datasets[] = array($dataset);
|
||||
}
|
||||
return $datasets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a quiz add questions to it, walk through quiz attempts and then check results.
|
||||
*
|
||||
* @param PHPUnit_Extensions_Database_DataSet_ITable $qs questions to add to quiz, read from csv file "questionsXX.csv".
|
||||
* @param PHPUnit_Extensions_Database_DataSet_ITable $steps steps to simulate, read from csv file "stepsXX.csv".
|
||||
* @param PHPUnit_Extensions_Database_DataSet_ITable $results results expected, read from csv file "resultsXX.csv".
|
||||
* @param PHPUnit_Extensions_Database_DataSet_ITable[] of data read from csv file "questionsXX.csv",
|
||||
* "stepsXX.csv" and "resultsXX.csv".
|
||||
* @dataProvider get_data_for_walkthrough
|
||||
*/
|
||||
public function test_walkthrough_from_csv($qs, $steps, $results) {
|
||||
global $DB;
|
||||
public function test_walkthrough_from_csv($csvdata) {
|
||||
|
||||
// CSV data files for these tests were generated using :
|
||||
// https://github.com/jamiepratt/moodle-quiz-tools/tree/master/responsegenerator
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
question_bank::get_qtype('random')->clear_caches_before_testing();
|
||||
|
||||
$this->create_quiz($qs);
|
||||
$this->create_quiz($csvdata['questions']);
|
||||
|
||||
$attemptids = $this->walkthrough_attempts($csvdata['steps']);
|
||||
|
||||
$this->check_attempts_results($csvdata['results'], $attemptids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $steps PHPUnit_Extensions_Database_DataSet_ITable the step data from the csv file.
|
||||
* @return array attempt no as in csv file => the id of the quiz_attempt as stored in the db.
|
||||
*/
|
||||
protected function walkthrough_attempts($steps) {
|
||||
global $DB;
|
||||
$attemptids = array();
|
||||
for ($rowno = 0; $rowno < $steps->getRowCount(); $rowno++) {
|
||||
|
||||
$step = $this->explode_dot_separated_keys_to_make_subindexs($steps->getRow($rowno));
|
||||
// Find existing user or make a new user to do the quiz.
|
||||
$username = array('firstname' => $step['firstname'],
|
||||
'lastname' => $step['lastname']);
|
||||
'lastname' => $step['lastname']);
|
||||
|
||||
if (!$user = $DB->get_record('user', $username)) {
|
||||
$user = $this->getDataGenerator()->create_user($username);
|
||||
@@ -242,15 +264,20 @@ class mod_quiz_attempt_walkthrough_from_csv_testcase extends advanced_testcase {
|
||||
$attemptobj = quiz_attempt::create($attempt->id);
|
||||
$attemptobj->process_finish($timenow, false);
|
||||
|
||||
|
||||
}
|
||||
return $attemptids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $results PHPUnit_Extensions_Database_DataSet_ITable the results data from the csv file.
|
||||
* @param $attemptids array attempt no as in csv file => the id of the quiz_attempt as stored in the db.
|
||||
*/
|
||||
protected function check_attempts_results($results, $attemptids) {
|
||||
for ($rowno = 0; $rowno < $results->getRowCount(); $rowno++) {
|
||||
$result = $this->explode_dot_separated_keys_to_make_subindexs($results->getRow($rowno));
|
||||
// Re-load quiz attempt data.
|
||||
$attemptobj = quiz_attempt::create($attemptids[$result['quizattempt']]);
|
||||
$this->check_attempt_results($result, $attemptobj);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +306,7 @@ class mod_quiz_attempt_walkthrough_from_csv_testcase extends advanced_testcase {
|
||||
break;
|
||||
default :
|
||||
throw new coding_exception('Unknown slots sub field column in csv file '
|
||||
.s($slotfieldname));
|
||||
.s($slotfieldname));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user