MDL-81114 question: fix selection of random questions with draft status

We need to pick the latest 'ready' version of each question
(not questions where the latest version is ready).

There are test of the behaviour of random_question_loader, and
then a test in the quiz to prove it works in use.
This commit is contained in:
Tim Hunt
2024-03-11 10:45:19 +00:00
parent db8d3fef9c
commit 36e03243da
4 changed files with 108 additions and 9 deletions
+48
View File
@@ -16,8 +16,11 @@
namespace mod_quiz;
use core_question\local\bank\condition;
use core_question\local\bank\question_version_status;
use core_question_generator;
use mod_quiz\output\view_page;
use mod_quiz_generator;
use question_engine;
defined('MOODLE_INTERNAL') || die();
@@ -25,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
/**
* Tests for the quiz_attempt class.
*
@@ -32,6 +36,7 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
* @category test
* @copyright 2014 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_quiz\quiz_attempt
*/
class attempt_test extends \advanced_testcase {
@@ -378,6 +383,49 @@ class attempt_test extends \advanced_testcase {
$this->assertEquals($student1->id, $step->get_user_id());
}
/**
* Test quiz_prepare_and_start_new_attempt function
*/
public function test_quiz_prepare_and_start_new_attempt_random_draft() {
$this->resetAfterTest();
$this->setAdminUser();
// Create course.
$course = $this->getDataGenerator()->create_course();
// Create quiz.
/** @var mod_quiz_generator $quizgenerator */
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(['course' => $course->id]);
// Create question with 2 versions. V1 ready. V2 draft.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $questiongenerator->create_question_category();
$question = $questiongenerator->create_question('shortanswer', null,
['questiontext' => 'V1', 'category' => $category->id]);
$questiongenerator->update_question($question, null,
['questiontext' => 'V2', 'status' => question_version_status::QUESTION_STATUS_DRAFT]);
// Add a random question form that category.
$filtercondition = [
'filter' => [
'category' => [
'jointype' => condition::JOINTYPE_DEFAULT,
'values' => [$category->id],
'filteroptions' => ['includesubcategories' => false],
],
],
];
$quizobj = quiz_settings::create($quiz->id);
$quizobj->get_structure()->add_random_questions(1, 1, $filtercondition);
$quizobj->get_grade_calculator()->recompute_quiz_sumgrades();
// Create an attempt.
$quizobj = quiz_settings::create($quiz->id);
$attempt = quiz_prepare_and_start_new_attempt($quizobj, 1, null);
$this->assertEquals(1, $attempt->preview);
}
/**
* Test check_page_access function
* @covers \quiz_attempt::check_page_access
@@ -191,8 +191,8 @@ trait quiz_question_helper_test_trait {
* @return void
*/
protected function add_random_questions(int $quizid, int $page, int $categoryid, int $number): void {
$settings = quiz_settings::create($quizid);
$structure = \mod_quiz\structure::create_for_quiz($settings);
$quizobj = quiz_settings::create($quizid);
$structure = $quizobj->get_structure();
$filtercondition = [
'filter' => [
'category' => [
@@ -232,15 +232,14 @@ class random_question_loader {
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
WHERE q.parent = :noparent
AND qv.status = :ready
AND qv.version = (
SELECT MAX(v.version)
FROM {question_versions} v
JOIN {question_bank_entries} be ON be.id = v.questionbankentryid
WHERE be.id = qbe.id
)
$qtypecondition
$filtercondition
AND qv.version = (
SELECT MAX(version)
FROM {question_versions}
WHERE questionbankentryid = qbe.id
AND status = :ready
)
ORDER BY previous_attempts
", array_merge(
@@ -120,6 +120,58 @@ final class random_question_loader_test extends \advanced_testcase {
$this->assertNull($loader->get_next_filtered_question_id($filters));
}
public function test_draft_questions_not_returned(): void {
$this->resetAfterTest();
$this->setAdminUser();
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
// Create a question in draft state.
$category = $questiongenerator->create_question_category();
$questiongenerator->create_question('shortanswer', null,
['category' => $category->id, 'status' => question_version_status::QUESTION_STATUS_DRAFT]);
// Try to a random question from that category - should not be one.
$filtercondition = [
'filter' => [
'category' => [
'jointype' => condition::JOINTYPE_DEFAULT,
'values' => [$category->id],
'filteroptions' => ['includesubcategories' => false],
],
],
];
$loader = new random_question_loader(new qubaid_list([]));
$this->assertNull($loader->get_next_filtered_question_id($filtercondition));
}
public function test_questions_with_later_draft_version_is_returned(): void {
$this->resetAfterTest();
$this->setAdminUser();
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
// Create a question in draft state.
$category = $questiongenerator->create_question_category();
$question = $questiongenerator->create_question('shortanswer', null,
['questiontext' => 'V1', 'category' => $category->id]);
$questiongenerator->update_question($question, null,
['questiontext' => 'V2', 'status' => question_version_status::QUESTION_STATUS_DRAFT]);
// Try to a random question from that category - should get V1.
$filtercondition = [
'filter' => [
'category' => [
'jointype' => condition::JOINTYPE_DEFAULT,
'values' => [$category->id],
'filteroptions' => ['includesubcategories' => false],
],
],
];
$loader = new random_question_loader(new qubaid_list([]));
$this->assertEquals($question->id, $loader->get_next_filtered_question_id($filtercondition));
}
public function test_one_question_category_returns_that_q_then_null(): void {
$this->resetAfterTest();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');