Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Question types: Difference between revisions

From MoodleDocs
No edit summary
Line 8: Line 8:
{{Work in progress}}
{{Work in progress}}


To learn to write question types, you are highly encouraged to read the code of some of the existing question types in the Moodle code base.
To learn to write question types, you are highly encouraged to read the code of some of the existing question types in the Moodle code base, also there are many more examples of question types in the [https://github.com/moodleou/ Open University github repository].


Also note that all the question engine code has extensive PHP documenter comments that should explain the purpose of every class and method. This document is supposed to provide an overview of the key points to get you started. It does not attempt to duplicate all the details in the PHPdocs.
Also note that all the question engine code has extensive PHP documenter comments that should explain the purpose of every class and method. This document is supposed to provide an overview of the key points to get you started. It does not attempt to duplicate all the details in the PHPdocs.


This document assumes that you understand the data model, where a question attempt comprises a number of steps, and each step has some properties like a state and a mark, and an array of submitted data.
This document assumes that you understand the data model, where a question attempt comprises a number of steps, and each step has some properties like a state and a mark, and an array of submitted data. [https://docs.moodle.org/dev/Question_Engine_2:Overview See the question engine overview doc for background].





Revision as of 10:52, 31 January 2013

This page explains how to write a question type that works with the new Moodle question engine, the question engine introduced with Moodle 2.1 .

For instructions on making a question type for versions of Moodle prior to Moodle 2.1, see Question_type_plugin_how_to.

Previous section: Developing a Question Behaviour

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.


To learn to write question types, you are highly encouraged to read the code of some of the existing question types in the Moodle code base, also there are many more examples of question types in the Open University github repository.

Also note that all the question engine code has extensive PHP documenter comments that should explain the purpose of every class and method. This document is supposed to provide an overview of the key points to get you started. It does not attempt to duplicate all the details in the PHPdocs.

This document assumes that you understand the data model, where a question attempt comprises a number of steps, and each step has some properties like a state and a mark, and an array of submitted data. See the question engine overview doc for background.


File layout

Question types live in a folder in question/type. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the question/type/mytype/ folder we would have:

questiontype.php
Defines the qtype_mytype class. This must extend question_type.
question.php
This contains the definition of the qtype_mytype_question class, which should extend the question_definition base class.
renderer.php
This contains the definition of the qtype_mytype_renderer class, which should extend the qtype_renderer base class.
tests/...
Contains the unit tests for this question type. You are strongly encouraged to write thorough unit tests to ensure the correctness of your question type. Note the change from using simpletest/ directory since we changed to PHPUnit from Simple Test unit test library in Moodle 2.3.
lang/en/qtype_myqtype.php
English language strings for this question type. You can, of course, include other languages too. The language file must define at least the string giving the model a name, for example $string['addingmyqtype'] = 'Adding a My question type';, $string['editingmyqtype'] = 'Editing a My question type'; and $string['myqtype'] = 'My question type';
lib.php
You might put some constants, classes and functions in here for inclusion across other files in your question type. There is a hook in here that is called by the question engine to allow access to files used by questions.
db/install.xml, db/upgrade.php
For creating any database tables required, as normal. See #Database_tables below.
db/access.php
Defines any capabilities required by this question type. This is very rarely needed.
version.php
version no of the question type. Also you can included in here which version no of core Moodle and/or other question types this module requires. Bumping up the question version will trigger the appropriate code in upgrade.php to be run when someone accesses {yourwwwroot}/admin/.

Database tables

Note that question types should only have database tables for the question definition. All runtime data is managed by the question engine.

Question definitions should use the core table question, and can use the core table question_answers. You only need to define database tables if your question definition requires extra information that cannot be stored in either of these.


Question type class

This class represents the question type. It is responsible for loading and saving instances of questions of this class. It is also responsible for backing them up and restoring them. It also provides meta-data about the question type.


TODO

Question definition class

This holds the definition of a particular question of this type. There may also be some methods to perform processing. For example grade_responses.


TODO

Renderer class

Renderers are all about generating HTML output. The overall output of questions is controlled by the core_question_renderer::question(...), which in turn calls other methods of itself, the question type renderer and the behaviour renderer, to generate the various bits of output. See this overview of the parts of a question.

Once again, in what follows, I only list the methods your are most likely to want to override.


formulation_and_controls

This displays the question text, and the controls the student will use to input their response. Some question types choose to display some feedback embedded in this area, for example ticks and crosses next to parts of the student's response.

The output code must respect the question_display_options and only reveal as much information as the calling code wants revealed. For example, the teacher creating a quiz may not want the correct answer revealed until after the quiz close date. Also, when outputting the controls, you need to respect the ->readonly option.

specific_feedback

Anything returned by this method is included in the 'outcome' area of the question, it is some feedback that particularly relates to the response the student gave. This method is only called if the display options allow this to be shows, so you don't have to worry about testing that.


correct_response

This would also be included in the 'outcome' area. This should be an automatically generated (from the question definition) display of what the correct answer to the question is.


Unit tests

For a general introduction, see the Moodle unit testing documentation note since 2.3 we use the PHPUnit testing library and no longer use simpletest.

The most important parts of your question type to test are the parts of the question_definition class that process the students responses, including the compare and grade methods. The best way to start is probably to look at the tests for some of the standard question types. There are some nice examples of question walk through unit tests in the core questions and also in the OU github repository.

Advanced ideas

Note that there is actually no reason why you should only have a single question_definition class for your question type. You may decide, depending on the question options, to use different definition classes where question options cause questions to behave in different ways. The multiple-choice question type does this, using different definition and renderer classes for single-response and multiple-response questions (but with common subclasses). This is possible because your question type can override the question_type::make_question_instance and question_definition::get_renderer methods.


Testing a question type

The following provides a thorough test of a new question type.

  1. Create some new questions of your type, exercising each significantly different combination of options.
  2. Go back to the editing form for each question to make sure that the options were saved accurately and that you can change them and that the changes are then saved.
  3. Try typing invalid input into the editing form, and ensure it is rejected.
  4. Preview each of your new questions using a variety of question behaviours. Check the mark and feedback for a range of correct and incorrect responses.
  5. Add your questions to some quizzes, using a range of behaviours, and different numbers of questions per page.
  6. Preview those quizzes several times, entering a range of correct and incorrect responses.
  7. Now log in as a student and take the quizzes for real.
  8. If the question type uses comples CSS or JavaScript, repeat this testing in different web browsers.
  9. View all of the quiz reports, and ensure that they correctly display the information about your questions.
  10. Backup the course, restore it as a new course, and ensure that all your questions have been copied across accurately.
  11. Export your questions from the original course to each of the import/export formats your support. Import these questions to a new question category, and ensure they have been copied accurately (within the limits to which your question type can be represented in each format).
  12. Edit the questions so that there is a link to another part of the course (e.g. a Page resource) in every place that HTML can be entered. Repeat the backup and restore test and verify that the URLs in the restored question have been updated to point to the new copy of the Page resource in the new course.
  13. Edit the question to add an image to every HTML field that supports it. Repeat the Editing, Preview, Backup/restore and Export/import tests, and verify that the images always work, and that you don't end up with broken image links.
  14. Move the category containing the questions with images to a new context in the question bank, and make sure that the image links don't break.
  15. Check that all the unit tests for your question type pass.
  16. Run code-checker (https://moodle.org/plugins/view.php?plugin=local_codechecker) over your plugin to check the coding style.
  17. Check your question type against Accessibility guidelines, for example the Web Content Accessibility Guidelines.

Converting a Moodle 2.0 question type

1. Change the class definition in questiontype.php from

class question_myqtype_qtype extends default_questiontype {

to

class qtype_myqtype extends question_type {


2. Create new renderer.php and question.php files, with a suitable blank class definition in them. (Perhaps copy the files from another question type, then delete everything in the class.)


3. Fill in the the question definition class, including:

3a. appropriate fields to store the question definition.

3b. create start_attempt, based on the old create_session_and_responses.

3c. create apply_attempt_state, based on the old restore_session_and_responses.

3d. Implement the grading logic get_expected_data, is_complete_response, is_gradable_response, is_same_response, grade_response, get_num_parts_right, clear_wrong_from_response. Some of this will be based on the old grade_responses method. You may also find some of the necessary code mixed into places like print_question_formulation_and_controls.

3e. Implement the reporting functionality get_correct_response, get_question_summary, summarise_response. Some of this may be related to the old grading methods.

3f. Write a test helper class to create one or more typical test instances of your question definition class.

3g. Write unit tests for the grading and reporting methods.


4. Copy all the code from print_question_formulation_and_controls and display.html, and related methods, and split it into the appropriate methods in the renderer class.


5. Write one or more walk-through tests that take instances of your question with different behaviours.


6. Implement initialise_question_instance to populate instances of your question definition class from the data returned by get_question_options.


7. Copy check_file_access from the question type class to the question definition class, and update it.


8. Delete all the old qtype_myqtype_question methods that are no longer used.

9. Add things like hints to the question_edit_myqtype_form class. Look for opportunities to improve the existing code by using the helper methods like add_combined_feedback_fields, data_preprocessing_answers.

10. Note that question_type::get_editing_head_contributions no longer exists, because it is no longer necessary with the new mechanisms for handling CSS and JavaScript in Moodle 2.x. Any styles you put in question/type/mytype/styles.css will be included on every page anyway, and you can use $PAGE->requires->js_init_call() in, for example, the form definition, to load your JavaScript.

See also

Next section: Using the question engine from a module.

  • The PHP documenter comments that explain the purposes of every method in the question engine code.
  • Back to Question Engine 2