* @param object $attempt
* @param integer $attemptnumber starting from 1
* @param integer $timenow the attempt start time
+ * @param array $questionids slot number => question id. Used for random questions, to force the choice of a particular actual
+ * question. Intended for testing purposes only.
+ * @throws moodle_exception
* @return object modified attempt object
- * @throws moodle_exception if a random question exhausts the available questions
*/
-function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow) {
+function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow, $questionids = array()) {
// Fully load all the questions in this quiz.
$quizobj->preload_questions();
$quizobj->load_questions();
$question = question_bank::make_question($questiondata);
} else {
+ if (!isset($questionids[$quba->next_slot_number()])) {
+ $forcequestionid = null;
+ } else {
+ $forcequestionid = $questionids[$quba->next_slot_number()];
+ }
+
$question = question_bank::get_qtype('random')->choose_other_question(
- $questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers);
+ $questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers, $forcequestionid);
if (is_null($question)) {
throw new moodle_exception('notenoughrandomquestions', 'quiz',
$quizobj->view_url(), $questiondata);
$prefix1 = $quba->get_field_prefix(1);
$prefix2 = $quba->get_field_prefix(2);
-
$tosubmit = array(1 => array('answer' => 'frog'),
2 => array('answer' => '3.14'));
}
/**
- * Create a second quiz with questions and walk through a quiz attempt this time with a random question.
+ * Create a quiz with a random as well as other questions and walk through quiz attempts.
*/
public function test_quiz_with_random_question_attempt_walkthrough() {
global $SITE;
quiz_add_quiz_question($multichoicesingle->id, $quiz, 0);
- // Make a user to do the quiz.
- $user1 = $this->getDataGenerator()->create_user();
- $this->setUser($user1);
+ foreach (array($saq->id => 'frog', $numq->id => '3.14') as $randomqidtoselect => $randqanswer) {
+ // Make a new user to do the quiz each loop.
+ $user1 = $this->getDataGenerator()->create_user();
+ $this->setUser($user1);
- $quizobj = quiz::create($quiz->id, $user1->id);
+ $quizobj = quiz::create($quiz->id, $user1->id);
- // Start the attempt.
- $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
- $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
+ // Start the attempt.
+ $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
+ $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
- $timenow = time();
- $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
+ $timenow = time();
+ $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
- quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
+ quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow, array(1 => $randomqidtoselect));
- quiz_attempt_save_started($quizobj, $quba, $attempt);
+ quiz_attempt_save_started($quizobj, $quba, $attempt);
- // Process some responses from the student.
- $attemptobj = quiz_attempt::create($attempt->id);
+ // Process some responses from the student.
+ $attemptobj = quiz_attempt::create($attempt->id);
- $tosubmit = array();
- $selectedquestionid = $quba->get_question_attempt(1)->get_question()->id;
- if ($selectedquestionid == $numq->id) {
- $tosubmit[1] = array('answer' => '3.14');
- } else {
- $tosubmit[1] = array('answer' => 'frog');
- }
- $tosubmit[2] = array(
- 0 => 'amphibian',
- 1 => 'mammal',
- 2 => 'amphibian');
- $tosubmit[3] = array('1', '0', '1', '0'); // First and third choice.
- $tosubmit[4] = array('answer' => 0); // The first choice.
+ $tosubmit = array();
+ $selectedquestionid = $quba->get_question_attempt(1)->get_question()->id;
+ $tosubmit[1] = array('answer' => $randqanswer);
+ $tosubmit[2] = array(
+ 0 => 'amphibian',
+ 1 => 'mammal',
+ 2 => 'amphibian');
+ $tosubmit[3] = array('1', '0', '1', '0'); // First and third choice.
+ $tosubmit[4] = array('answer' => 0); // The first choice.
- $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
+ $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
- // Finish the attempt.
- $attemptobj = quiz_attempt::create($attempt->id);
- $attemptobj->process_finish($timenow, false);
+ // Finish the attempt.
+ $attemptobj = quiz_attempt::create($attempt->id);
+ $attemptobj->process_finish($timenow, false);
- // Re-load quiz attempt data.
- $attemptobj = quiz_attempt::create($attempt->id);
+ // Re-load quiz attempt data.
+ $attemptobj = quiz_attempt::create($attempt->id);
- // Check that results are stored as expected.
- $this->assertEquals(1, $attemptobj->get_attempt_number());
- $this->assertEquals(4, $attemptobj->get_sum_marks());
- $this->assertEquals(true, $attemptobj->is_finished());
- $this->assertEquals($timenow, $attemptobj->get_submitted_date());
- $this->assertEquals($user1->id, $attemptobj->get_userid());
+ // Check that results are stored as expected.
+ $this->assertEquals(1, $attemptobj->get_attempt_number());
+ $this->assertEquals(4, $attemptobj->get_sum_marks());
+ $this->assertEquals(true, $attemptobj->is_finished());
+ $this->assertEquals($timenow, $attemptobj->get_submitted_date());
+ $this->assertEquals($user1->id, $attemptobj->get_userid());
- // Check quiz grades.
- $grades = quiz_get_user_grades($quiz, $user1->id);
- $grade = array_shift($grades);
- $this->assertEquals(100.0, $grade->rawgrade);
+ // Check quiz grades.
+ $grades = quiz_get_user_grades($quiz, $user1->id);
+ $grade = array_shift($grades);
+ $this->assertEquals(100.0, $grade->rawgrade);
- // Check grade book.
- $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $quiz->id, $user1->id);
- $gradebookitem = array_shift($gradebookgrades->items);
- $gradebookgrade = array_shift($gradebookitem->grades);
- $this->assertEquals(100, $gradebookgrade->grade);
+ // Check grade book.
+ $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $quiz->id, $user1->id);
+ $gradebookitem = array_shift($gradebookgrades->items);
+ $gradebookgrade = array_shift($gradebookitem->grades);
+ $this->assertEquals(100, $gradebookgrade->grade);
+ }
}
}
/**
* Load the definition of another question picked randomly by this question.
- * @param object $questiondata the data defining a random question.
- * @param array $excludedquestions of question ids. We will no pick any
- * question whose id is in this list.
- * @param bool $allowshuffle if false, then any shuffle option on the
- * selected quetsion is disabled.
+ * @param object $questiondata the data defining a random question.
+ * @param array $excludedquestions of question ids. We will no pick any question whose id is in this list.
+ * @param bool $allowshuffle if false, then any shuffle option on the selected quetsion is disabled.
+ * @param null|integer $forcequestionid if not null then force the picking of question with id $forcequestionid.
+ * @throws coding_exception
* @return question_definition|null the definition of the question that was
* selected, or null if no suitable question could be found.
*/
- public function choose_other_question($questiondata, $excludedquestions, $allowshuffle = true) {
+ public function choose_other_question($questiondata, $excludedquestions, $allowshuffle = true, $forcequestionid = null) {
$available = $this->get_available_questions_from_category($questiondata->category,
!empty($questiondata->questiontext));
shuffle($available);
+ if ($forcequestionid !== null) {
+ $forcedquestionkey = array_search($forcequestionid, $available);
+ if ($forcedquestionkey !== false) {
+ unset($available[$forcedquestionkey]);
+ array_unshift($available, $forcequestionid);
+ } else {
+ throw new coding_exception('thisquestionidisnotavailable', $forcequestionid);
+ }
+ }
+
foreach ($available as $questionid) {
if (in_array($questionid, $excludedquestions)) {
continue;