Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/question/engine/simpletest/testunitofwork.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 require_once(dirname(__FILE__) . '/../lib.php');
00030 require_once(dirname(__FILE__) . '/helpers.php');
00031 
00032 
00040 class testable_question_engine_unit_of_work extends question_engine_unit_of_work {
00041     public function get_modified() {
00042         return $this->modified;
00043     }
00044 
00045     public function get_attempts_added() {
00046         return $this->attemptsadded;
00047     }
00048 
00049     public function get_attempts_modified() {
00050         return $this->attemptsmodified;
00051     }
00052 
00053     public function get_steps_added() {
00054         return $this->stepsadded;
00055     }
00056 
00057     public function get_steps_modified() {
00058         return $this->stepsmodified;
00059     }
00060 
00061     public function get_steps_deleted() {
00062         return $this->stepsdeleted;
00063     }
00064 }
00065 
00066 
00073 class question_engine_unit_of_work_test extends data_loading_method_test_base {
00075     protected $quba;
00076 
00078     protected $slot;
00079 
00081     protected $observer;
00082 
00083     public function setUp() {
00084         // Create a usage in an initial state, with one shortanswer question added,
00085         // and attempted in interactive mode submitted responses 'toad' then 'frog'.
00086         // Then set it to use a new unit of work for any subsequent changes.
00087         // Create a short answer question.
00088         $question = test_question_maker::make_question('shortanswer');
00089         $question->hints = array(
00090             new question_hint(0, 'This is the first hint.', FORMAT_HTML),
00091             new question_hint(0, 'This is the second hint.', FORMAT_HTML),
00092         );
00093         $question->id = -1;
00094         question_bank::start_unit_test();
00095         question_bank::load_test_question_data($question);
00096 
00097         $this->setup_initial_test_state($this->get_test_data());
00098      }
00099 
00100     public function testDown() {
00101         question_bank::end_unit_test();
00102     }
00103 
00104     protected function setup_initial_test_state($testdata) {
00105         $records = new test_recordset($testdata);
00106 
00107         $this->quba = question_usage_by_activity::load_from_records($records, 1);
00108 
00109         $this->slot = 1;
00110         $this->observer = new testable_question_engine_unit_of_work($this->quba);
00111         $this->quba->set_observer($this->observer);
00112     }
00113 
00114     protected function get_test_data() {
00115         return array(
00116         array('qubaid', 'contextid', 'component', 'preferredbehaviour',
00117                                                 'questionattemptid', 'contextid', 'questionusageid', 'slot',
00118                                                                'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
00119                                                                                                               'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
00120                                                                                                                                      'attemptstepid', 'sequencenumber', 'state', 'fraction',
00121                                                                                                                                                                      'timecreated', 'userid', 'name', 'value'),
00122         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo',             null, 1256233700, 1, '-_triesleft', 3),
00123         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo',             null, 1256233720, 1, 'answer',     'toad'),
00124         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo',             null, 1256233720, 1, '-submit',     1),
00125         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo',             null, 1256233720, 1, '-_triesleft', 1),
00126         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 3, 2, 'todo',             null, 1256233740, 1, '-tryagain',   1),
00127         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 3, 'gradedright',      null, 1256233790, 1, 'answer',     'frog'),
00128         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 3, 'gradedright', 1.0000000, 1256233790, 1, '-finish',     1),
00129         );
00130     }
00131 
00132     public function test_initial_state() {
00133         $this->assertFalse($this->observer->get_modified());
00134         $this->assertEqual(0, count($this->observer->get_attempts_added()));
00135         $this->assertEqual(0, count($this->observer->get_attempts_modified()));
00136         $this->assertEqual(0, count($this->observer->get_steps_added()));
00137         $this->assertEqual(0, count($this->observer->get_steps_modified()));
00138         $this->assertEqual(0, count($this->observer->get_steps_deleted()));
00139     }
00140 
00141     public function test_update_usage() {
00142 
00143         $this->quba->set_preferred_behaviour('deferredfeedback');
00144 
00145         $this->assertTrue($this->observer->get_modified());
00146     }
00147 
00148     public function test_add_question() {
00149 
00150         $slot = $this->quba->add_question(test_question_maker::make_question('truefalse'));
00151 
00152         $newattempts = $this->observer->get_attempts_added();
00153         $this->assertEqual(1, count($newattempts));
00154         $this->assertIdentical($this->quba->get_question_attempt($slot), reset($newattempts));
00155         $this->assertIdentical($slot, key($newattempts));
00156     }
00157 
00158     public function test_add_and_start_question() {
00159 
00160         $slot = $this->quba->add_question(test_question_maker::make_question('truefalse'));
00161                 $this->quba->start_question($slot);
00162 
00163         // The point here is that, although we have added a step, it is not listed
00164         // separately becuase it is part of a newly added attempt, and all steps
00165         // for a newly added attempt are automatically added to the DB, so it does
00166         // not need to be tracked separately.
00167         $newattempts = $this->observer->get_attempts_added();
00168         $this->assertEqual(1, count($newattempts));
00169         $this->assertIdentical($this->quba->get_question_attempt($slot),
00170                 reset($newattempts));
00171         $this->assertIdentical($slot, key($newattempts));
00172         $this->assertEqual(0, count($this->observer->get_steps_added()));
00173     }
00174 
00175     public function test_process_action() {
00176 
00177         $this->quba->manual_grade($this->slot, 'Acutally, that is not quite right', 0.5);
00178 
00179         // Here, however, were we are adding a step to an existing qa, we do need to track that.
00180         $this->assertEqual(0, count($this->observer->get_attempts_added()));
00181 
00182         $updatedattempts = $this->observer->get_attempts_modified();
00183         $this->assertEqual(1, count($updatedattempts));
00184 
00185         $updatedattempt = reset($updatedattempts);
00186         $this->assertIdentical($this->quba->get_question_attempt($this->slot), $updatedattempt);
00187         $this->assertIdentical($this->slot, key($updatedattempts));
00188 
00189         $newsteps = $this->observer->get_steps_added();
00190         $this->assertEqual(1, count($newsteps));
00191 
00192         list($newstep, $qaid, $seq) = reset($newsteps);
00193         $this->assertIdentical($this->quba->get_question_attempt($this->slot)->get_last_step(), $newstep);
00194     }
00195 
00196     public function test_regrade_same_steps() {
00197 
00198         // Change the question in a minor way and regrade.
00199         $this->quba->get_question($this->slot)->answer[14]->fraction = 0.5;
00200         $this->quba->regrade_all_questions();
00201 
00202         // Here, the qa, and all the steps, should be marked as updated.
00203         // Here, however, were we are adding a step to an existing qa, we do need to track that.
00204         $this->assertEqual(0, count($this->observer->get_attempts_added()));
00205         $this->assertEqual(0, count($this->observer->get_steps_added()));
00206         $this->assertEqual(0, count($this->observer->get_steps_deleted()));
00207 
00208         $updatedattempts = $this->observer->get_attempts_modified();
00209         $this->assertEqual(1, count($updatedattempts));
00210 
00211         $updatedattempt = reset($updatedattempts);
00212         $this->assertIdentical($this->quba->get_question_attempt($this->slot), $updatedattempt);
00213 
00214         $updatedsteps = $this->observer->get_steps_modified();
00215         $this->assertEqual($updatedattempt->get_num_steps(), count($updatedsteps));
00216 
00217         foreach ($updatedattempt->get_step_iterator() as $seq => $step) {
00218             $this->assertIdentical(array($step, $updatedattempt->get_database_id(), $seq),
00219                     $updatedsteps[$seq]);
00220         }
00221     }
00222 
00223     public function test_regrade_losing_steps() {
00224 
00225         // Change the question so that 'toad' is also right, and regrade. This
00226         // will mean that the try again, and second try states are no longer
00227         // needed, so they should be dropped.
00228         $this->quba->get_question($this->slot)->answers[14]->fraction = 1;
00229         $this->quba->regrade_all_questions();
00230 
00231         $this->assertEqual(0, count($this->observer->get_attempts_added()));
00232         $this->assertEqual(0, count($this->observer->get_steps_added()));
00233 
00234         $updatedattempts = $this->observer->get_attempts_modified();
00235         $this->assertEqual(1, count($updatedattempts));
00236 
00237         $updatedattempt = reset($updatedattempts);
00238         $this->assertIdentical($this->quba->get_question_attempt($this->slot), $updatedattempt);
00239 
00240         $updatedsteps = $this->observer->get_steps_modified();
00241         $this->assertEqual($updatedattempt->get_num_steps(), count($updatedsteps));
00242 
00243         foreach ($updatedattempt->get_step_iterator() as $seq => $step) {
00244             $this->assertIdentical(array($step, $updatedattempt->get_database_id(), $seq),
00245                     $updatedsteps[$seq]);
00246         }
00247 
00248         $deletedsteps = $this->observer->get_steps_deleted();
00249         $this->assertEqual(2, count($deletedsteps));
00250 
00251         $firstdeletedstep = reset($deletedsteps);
00252         $this->assertEqual(array('-tryagain' => 1), $firstdeletedstep->get_all_data());
00253 
00254         $seconddeletedstep = end($deletedsteps);
00255         $this->assertEqual(array('answer' => 'frog', '-finish' => 1),
00256                 $seconddeletedstep->get_all_data());
00257     }
00258 
00259     public function test_tricky_regrade() {
00260 
00261         // The tricky thing here is that we take a half-complete question-attempt,
00262         // and then as one transaction, we submit some more responses, and then
00263         // change the question attempt as in test_regrade_losing_steps, and regrade
00264         // before the steps are even written to the database the first time.
00265         $somedata = $this->get_test_data();
00266         $somedata = array_slice($somedata, 0, 5);
00267         $this->setup_initial_test_state($somedata);
00268 
00269         $this->quba->process_action($this->slot, array('-tryagain' => 1));
00270         $this->quba->process_action($this->slot, array('answer' => 'frog', '-submit' => 1));
00271         $this->quba->finish_all_questions();
00272 
00273         $this->quba->get_question($this->slot)->answers[14]->fraction = 1;
00274         $this->quba->regrade_all_questions();
00275 
00276         $this->assertEqual(0, count($this->observer->get_attempts_added()));
00277 
00278         $updatedattempts = $this->observer->get_attempts_modified();
00279         $this->assertEqual(1, count($updatedattempts));
00280 
00281         $updatedattempt = reset($updatedattempts);
00282         $this->assertIdentical($this->quba->get_question_attempt($this->slot), $updatedattempt);
00283 
00284         $this->assertEqual(0, count($this->observer->get_steps_added()));
00285 
00286         $updatedsteps = $this->observer->get_steps_modified();
00287         $this->assertEqual($updatedattempt->get_num_steps(), count($updatedsteps));
00288 
00289         foreach ($updatedattempt->get_step_iterator() as $seq => $step) {
00290             $this->assertIdentical(array($step, $updatedattempt->get_database_id(), $seq),
00291                     $updatedsteps[$seq]);
00292         }
00293 
00294         $this->assertEqual(0, count($this->observer->get_steps_deleted()));
00295     }
00296 }
 All Data Structures Namespaces Files Functions Variables Enumerations