Chapitre 11.1 — QTI : échanger des tests
⏱️ TL;DR — QTI (Question & Test Interoperability, 1EdTech) est le standard qui rend tes questions et tes tests portables entre plateformes : au lieu de recréer un QCM à la main dans chaque LMS, tu l’exportes une fois et il s’importe partout. L’unité de base est l’
assessmentItem(une question) : unitemBody(l’énoncé + une interaction commechoiceInteractionoutextEntryInteraction), uneresponseDeclaration(la bonne réponse), uneresponseProcessing(comment noter), uneoutcomeDeclaration(le score produit). On regroupe des items dans unassessmentTest. Deux versions vivantes : QTI 2.1 (verbeux, éprouvé) et QTI 3.0 (2022, alignée HTML5, éléments préfixésqti-). QTI vit rarement seul : il voyage dans un Common Cartridge ou s’importe dans la banque de questions d’un LMS.
🎯 Objectifs
- Expliquer à quoi sert QTI et pourquoi un QCM « portable » vaut mieux qu’un QCM ressaisi partout.
- Lire et écrire un
assessmentItem:itemBody, interaction,responseDeclaration,outcomeDeclaration,responseProcessing. - Nommer les interactions courantes (
choiceInteraction,textEntryInteraction,matchInteraction…). - Comprendre le rôle de la
responseProcessing(templatematch_correctvs logique sur mesure). - Distinguer QTI 2.1 et QTI 3.0, et savoir où vit un paquet QTI (Common Cartridge, LMS).
À quoi sert QTI
Tu as construit un test dans ton studio : dix questions, des QCM, des trous à remplir, une notation par question. Une école veut ce test dans son Moodle, une autre dans son Canvas, une troisième dans un outil maison. Sans standard, c’est trois ressaisies — et chaque correction de coquille est à refaire trois fois. QTI supprime ce mur : tu exportes le test une fois, au format QTI, et chaque plateforme conforme sait l’importer.
QTI décrit le contenu pédagogique d’une évaluation : l’énoncé, les choix, la bonne réponse, le barème, les retours (feedback). Il ne décrit ni l’apparence exacte (c’est le LMS qui met en page), ni le suivi de l’apprenant dans le temps (ça, c’est SCORM/xAPI/Caliper). QTI, c’est la question elle-même, rendue transportable.
💡 Réflexe — Sépare bien trois plans qu’on confond souvent : QTI = le contenu d’un test (questions, réponses, barème) ; AGS / OneRoster = la note qui en ressort et où elle atterrit ; SCORM / xAPI / Caliper = la trace de ce qu’a fait l’apprenant. Un même quiz peut être décrit en QTI, sa note renvoyée par AGS, et son passage tracé en xAPI. Trois standards, trois rôles.
L’assessmentItem : anatomie d’une question
Une question QTI, c’est quatre briques qui se répondent :
| Brique | Rôle | Élément |
|---|---|---|
| Le corps | L’énoncé + l’interaction que voit l’apprenant | itemBody (+ choiceInteraction, etc.) |
| La bonne réponse | Ce qui est attendu | responseDeclaration (+ correctResponse) |
| La notation | Comment transformer la réponse en score | responseProcessing |
| Le résultat | La ou les variables produites (score…) | outcomeDeclaration |
Voici un QCM complet en QTI 2.1. Lis-le de haut en bas : chaque bloc correspond à une ligne du tableau.
<?xml version="1.0" encoding="UTF-8"?>
<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1"
identifier="choice-capitale-fr"
title="Capitale de la France"
adaptive="false"
timeDependent="false">
<!-- Ce qui est attendu : la variable RESPONSE vaut ChoiceB -->
<responseDeclaration identifier="RESPONSE" cardinality="single" baseType="identifier">
<correctResponse>
<value>ChoiceB</value>
</correctResponse>
</responseDeclaration>
<!-- Le résultat produit : une variable SCORE (float), 0 par défaut -->
<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float">
<defaultValue>
<value>0</value>
</defaultValue>
</outcomeDeclaration>
<!-- Ce que voit l'apprenant : l'énoncé + l'interaction -->
<itemBody>
<p>Quelle est la capitale de la France ?</p>
<choiceInteraction responseIdentifier="RESPONSE" shuffle="true" maxChoices="1">
<simpleChoice identifier="ChoiceA">Lyon</simpleChoice>
<simpleChoice identifier="ChoiceB">Paris</simpleChoice>
<simpleChoice identifier="ChoiceC">Marseille</simpleChoice>
</choiceInteraction>
</itemBody>
<!-- Comment noter : template standard "réponse juste = 1, sinon 0" -->
<responseProcessing
template="http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct"/>
</assessmentItem>Décryptage des rouages :
identifier/title: l’ID machine et le titre humain de l’item. L’identifierest la clé référencée par unassessmentTest.responseDeclarationrelie le nom de la variable de réponse (RESPONSE, réutilisé par l’interaction viaresponseIdentifier) à la bonne réponse (correctResponse→ChoiceB). Sacardinalitydit si on attend une valeur (single), plusieurs (multiple), ordonnée (ordered) ; sonbaseTypedit le type (identifier,string,integer,float…).outcomeDeclarationdéclare la variable produite — iciSCORE. C’est elle que le LMS lira pour connaître le résultat.itemBodycontient un sous-ensemble de HTML (p,img, tableaux…) plus l’interaction. IcichoiceInteraction(un QCM) avecmaxChoices="1"(une seule réponse) etshuffle="true"(choix mélangés).responseProcessingest la logique de notation. Ici on invoque un template standard,match_correct: « siRESPONSEégalecorrectResponse,SCORE= 1, sinon 0 ». Pas besoin de la réécrire : QTI fournit des templates prêts.
⚠️ Piège — Croire que
simpleChoiceporte « la bonne réponse ». Non : lessimpleChoicene sont que les options affichées. La bonne réponse vit ailleurs, danscorrectResponse(ChoiceB), reliée par l’identifierdu choix. Séparer l’énoncé (itemBody) de la clé de correction (responseDeclaration) est voulu : ça permet de mélanger les choix (shuffle) sans jamais trahir la réponse, et de livrer une version « sans corrigé » si besoin.
Les interactions : au-delà du QCM
Le choiceInteraction n’est qu’une des interactions QTI. Chacune correspond à un type de question :
| Interaction | Type de question | Exemple |
|---|---|---|
choiceInteraction | QCM (choix unique ou multiple) | « Quelle est la capitale… » |
textEntryInteraction | Trou à remplir, réponse courte | « 2 + 2 = ___ » |
extendedTextInteraction | Réponse longue (rédaction) | « Explique en 5 lignes… » |
matchInteraction | Appariement (relier A à B) | Pays ↔ capitales |
orderInteraction | Remise en ordre | Trier des étapes |
inlineChoiceInteraction | Menu déroulant dans le texte | « La photosynthèse produit du [▾] » |
hotspotInteraction | Zone à cliquer sur une image | Pointer un organe |
Un trou à remplir avec textEntryInteraction a une particularité : l’interaction est dans le texte, et la notation se fait souvent sur une chaîne (baseType="string"), parfois avec une table de correspondance pour accepter des variantes (« Paris », « paris », « PARIS »).
<responseDeclaration identifier="RESPONSE" cardinality="single" baseType="string">
<correctResponse>
<value>Paris</value>
</correctResponse>
<mapping defaultValue="0">
<mapEntry mapKey="Paris" mappedValue="1"/>
<mapEntry mapKey="paris" mappedValue="1"/>
</mapping>
</responseDeclaration>
<itemBody>
<p>La capitale de la France est <textEntryInteraction responseIdentifier="RESPONSE" expectedLength="15"/>.</p>
</itemBody>Ici la notation utilisera le template map_response (au lieu de match_correct) : il lit la mapping et attribue le mappedValue correspondant à la saisie. C’est le mécanisme du crédit partiel et de la tolérance orthographique.
responseProcessing : la logique de notation
La responseProcessing transforme la réponse de l’apprenant en outcome (le SCORE). Deux voies :
- Un template standard — le plus courant.
match_correct(juste/faux) oumap_response(barème par unemapping). Une seule ligne, rien à écrire. - Une logique sur mesure — quand le barème est particulier (points négatifs, conditions croisées). On l’écrit avec
responseCondition/responseIf/setOutcomeValue:
<responseProcessing>
<responseCondition>
<responseIf>
<match>
<variable identifier="RESPONSE"/>
<correct identifier="RESPONSE"/>
</match>
<setOutcomeValue identifier="SCORE">
<baseValue baseType="float">2</baseValue>
</setOutcomeValue>
</responseIf>
<responseElse>
<setOutcomeValue identifier="SCORE">
<baseValue baseType="float">-0.5</baseValue>
</setOutcomeValue>
</responseElse>
</responseCondition>
</responseProcessing>Ici : bonne réponse → SCORE = 2 ; mauvaise → SCORE = -0,5 (malus). C’est le même modèle mental qu’un if/else, en XML.
💡 Réflexe — N’écris une
responseProcessingsur mesure que si un template ne suffit pas. 90 % des questions se notent avecmatch_correct(juste/faux) oumap_response(barème). Réserver le sur-mesure aux cas réels (malus, seuils) garde tes items lisibles et portables : un template standard est compris par tous les moteurs QTI, une logique exotique l’est parfois moins.
De la question au test : assessmentTest
Un assessmentItem, c’est une question. Un assessmentTest organise plusieurs items en une épreuve : sections, ordre, temps imparti, mode de navigation, et agrégation des scores.
<assessmentTest identifier="test-geo-6e" title="Évaluation géographie 6e">
<testPart identifier="part1" navigationMode="linear" submissionMode="individual">
<assessmentSection identifier="sec1" title="Capitales" visible="true">
<assessmentItemRef identifier="q1" href="items/choice-capitale-fr.xml"/>
<assessmentItemRef identifier="q2" href="items/textentry-capitale.xml"/>
</assessmentSection>
</testPart>
<outcomeProcessing>
<!-- somme des SCORE de chaque item -> SCORE total du test -->
</outcomeProcessing>
</assessmentTest>Points-clés :
- Le test ne recopie pas les questions : il les référence par
assessmentItemRef(hrefvers le fichier de l’item). Une question réutilisable vit dans un seul fichier. navigationMode(linear= on avance sans revenir en arrière ;nonlinear= navigation libre) etsubmissionMode(individual= correction question par question ;simultaneous= tout à la fin) définissent l’expérience.outcomeProcessingagrège les scores des items en un score de test (souvent une somme).
QTI 2.1 vs QTI 3.0
Les deux versions décrivent la même chose ; elles diffèrent surtout par la syntaxe.
| QTI 2.1 | QTI 3.0 (2022) | |
|---|---|---|
| Nommage des éléments | camelCase : assessmentItem, choiceInteraction | kebab-case préfixé : qti-assessment-item, qti-choice-interaction |
| Attributs | timeDependent, maxChoices | time-dependent, max-choices |
| Alignement | XML « historique » | Aligné HTML5 / web (intégration front plus naturelle) |
| Accessibilité, styles | Support de base | Renforcé (PNP, partage avec APIP) |
| Namespace | imsqti_v2p1 | imsqtiasi_v3p0 |
Le même QCM en QTI 3.0 :
<?xml version="1.0" encoding="UTF-8"?>
<qti-assessment-item xmlns="http://www.imsglobal.org/xsd/imsqtiasi_v3p0"
identifier="choice-capitale-fr"
title="Capitale de la France"
adaptive="false"
time-dependent="false">
<qti-response-declaration identifier="RESPONSE" cardinality="single" base-type="identifier">
<qti-correct-response>
<qti-value>ChoiceB</qti-value>
</qti-correct-response>
</qti-response-declaration>
<qti-outcome-declaration identifier="SCORE" cardinality="single" base-type="float">
<qti-default-value>
<qti-value>0</qti-value>
</qti-default-value>
</qti-outcome-declaration>
<qti-item-body>
<p>Quelle est la capitale de la France ?</p>
<qti-choice-interaction response-identifier="RESPONSE" shuffle="true" max-choices="1">
<qti-simple-choice identifier="ChoiceA">Lyon</qti-simple-choice>
<qti-simple-choice identifier="ChoiceB">Paris</qti-simple-choice>
<qti-simple-choice identifier="ChoiceC">Marseille</qti-simple-choice>
</qti-choice-interaction>
</qti-item-body>
<!-- template standard match_correct ; URI réalignée en v3, voir 1edtech.org -->
<qti-response-processing template="match_correct"/>
</qti-assessment-item>Même structure, même logique — seuls les noms changent. Qui comprend l’un comprend l’autre.
⚠️ Piège — Exporter en QTI 3.0 vers un LMS qui n’importe encore que QTI 2.1 (ou pire, une variante maison). Le support QTI varie beaucoup d’une plateforme à l’autre : certains n’ingèrent qu’un sous-ensemble, d’autres passent par leur propre format de banque de questions. Ne suppose jamais qu’« exporter en QTI » suffit : teste l’import réel sur le LMS cible, et garde sous la main une version 2.1 tant que le 3.0 n’est pas partout accepté.
Où vit un paquet QTI
QTI se transporte rarement « à nu ». On le rencontre :
- Dans un content package dédié : un
.zipavec unimsmanifest.xmlqui liste les items et tests (même idée de manifeste que SCORM, Partie 3). - Dans un Common Cartridge : le paquet de cours (chapitre suivant, 11.2) embarque volontiers ses tests au format QTI, aux côtés des ressources et des liens LTI.
- Importé dans un LMS : Moodle, Canvas et consorts savent (plus ou moins complètement) importer du QTI dans leur banque de questions, où les items deviennent réutilisables dans des quiz natifs.
🔌 Côté intégration — Pour un éditeur de contenu, exporter du QTI propre est un argument commercial : l’école n’est pas « prisonnière » de ton lecteur, elle récupère ses questions dans son LMS. Mais l’inverse t’engage : si tu vends un LMS, savoir importer du QTI (et pas juste ton format maison) élargit ton catalogue aux banques de questions du marché. 1EdTech certifie la conformité QTI ; le label rassure les acheteurs institutionnels échaudés par les imports ratés.
🧭 Sur FormaCampus — Le studio d’exercices de FormaCampus (celui qu’on a branché en outil LTI, Partie 10) sait aussi exporter ses tests en QTI. Une académie cliente ne veut pas d’un outil externe pour ses évaluations bac blanc : elle veut les questions dans son Moodle. FormaCampus génère un paquet QTI 2.1 (le plus sûr pour l’import Moodle), l’académie l’importe dans sa banque de questions, et compose ses propres quiz. Bonus : FormaCampus importe aussi du QTI, ce qui lui permet d’ingérer des banques de questions déjà produites par les enseignants. QTI dans les deux sens : import et export.
📚 La spec — QTI (Question & Test Interoperability) est publié par 1EdTech (
1edtech.org). Concepts stables :assessmentItem(itemBody, interactions,responseDeclaration,responseProcessing,outcomeDeclaration) etassessmentTest(testPart,assessmentSection,assessmentItemRef,outcomeProcessing). Versions 2.1 puis 3.0 (2022, alignée HTML5, élémentsqti-…, namespaceimsqtiasi_v3p0). Les templates deresponseProcessing(match_correct,map_response) et leurs URI exactes sont sur1edtech.org. QTI est souvent voisin d’APIP (accessibilité) ; ne pas confondre QTI (le contenu du test) avec le suivi de l’apprenant (SCORM/xAPI/Caliper).
✏️ Exercices
Exercice 1 — Lis l’item. On te donne cet extrait. Que vaut la bonne réponse, combien de choix l’apprenant peut-il cocher, et quel score obtient-il s’il répond juste ?
<responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="identifier">
<correctResponse>
<value>A</value>
<value>C</value>
</correctResponse>
</responseDeclaration>
<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float">
<defaultValue><value>0</value></defaultValue>
</outcomeDeclaration>
<itemBody>
<choiceInteraction responseIdentifier="RESPONSE" maxChoices="2">
<simpleChoice identifier="A">Réponse A</simpleChoice>
<simpleChoice identifier="B">Réponse B</simpleChoice>
<simpleChoice identifier="C">Réponse C</simpleChoice>
</choiceInteraction>
</itemBody>
<responseProcessing
template="http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct"/>✅ Solution
C’est un QCM à choix multiple (cardinality="multiple", maxChoices="2"). La bonne réponse est A et C (les deux value de correctResponse). L’apprenant peut cocher jusqu’à 2 choix. Avec le template match_correct, il obtient SCORE = 1 uniquement s’il coche exactement A et C (ni plus, ni moins) ; toute autre combinaison donne 0. match_correct est tout ou rien : pour du crédit partiel, il faudrait map_response avec une mapping.
Exercice 2 — Écris la question. Rédige un assessmentItem QTI 2.1 pour : « En quelle année a été signé le traité de Rome ? », réponse attendue 1957, saisie libre, notée 1 point si juste. Indique l’interaction et le template.
✅ Solution
Une saisie libre → textEntryInteraction, réponse de type string, notation par map_response (ou match_correct si une seule graphie suffit) :
<responseDeclaration identifier="RESPONSE" cardinality="single" baseType="string">
<correctResponse><value>1957</value></correctResponse>
<mapping defaultValue="0">
<mapEntry mapKey="1957" mappedValue="1"/>
</mapping>
</responseDeclaration>
<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float">
<defaultValue><value>0</value></defaultValue>
</outcomeDeclaration>
<itemBody>
<p>En quelle année a été signé le traité de Rome ?
<textEntryInteraction responseIdentifier="RESPONSE" expectedLength="4"/></p>
</itemBody>
<responseProcessing
template="http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response"/>L’interaction est dans la phrase (textEntryInteraction). Le template map_response lit la mapping : 1957 → 1 point, tout le reste → 0.
Exercice 3 — 2.1 ou 3.0 ? Une école cible utilise un vieux Moodle qui « importe du QTI », mais tu ne sais pas quelle version. Ton studio peut exporter en 2.1 ou 3.0. Que fais-tu ?
✅ Solution
Tu testes l’import réel sur une instance de la cible avant de livrer, et par défaut tu exportes en QTI 2.1 : c’est la version la plus largement supportée par les LMS existants, notamment les Moodle plus anciens. QTI 3.0 est plus moderne (aligné HTML5) mais son support d’import est inégal. Règle : ne jamais présumer qu’« exporter en QTI » suffit — la version et le sous-ensemble supporté varient. En cas de doute, 2.1 + test d’import réel.
🧠 Quiz de révision
1. Quelles sont les quatre briques d’un assessmentItem ?
assessmentItem ?itemBody (l’énoncé + l’interaction), responseDeclaration (la bonne réponse attendue), responseProcessing (la logique de notation), outcomeDeclaration (la variable produite, souvent SCORE). L’énoncé et la clé de correction sont volontairement séparés.
2. Où se trouve la bonne réponse d’un QCM QTI ?
Dans la responseDeclaration, à l’intérieur de correctResponse (value → l’identifier du bon simpleChoice). Pas dans les simpleChoice eux-mêmes, qui ne sont que les options affichées. Cette séparation permet de mélanger les choix (shuffle) sans trahir la réponse.
3. À quoi sert responseProcessing et quels templates standards existe-t-il ?
responseProcessing et quels templates standards existe-t-il ?Elle transforme la réponse en score. Deux templates courants : match_correct (juste = 1, faux = 0, tout ou rien) et map_response (barème/crédit partiel via une mapping). On peut aussi écrire une logique sur mesure (responseCondition/responseIf/setOutcomeValue) pour des cas particuliers (malus, seuils).
4. Quelle différence principale entre QTI 2.1 et QTI 3.0 ?
Surtout la syntaxe : QTI 2.1 en camelCase (assessmentItem, choiceInteraction) ; QTI 3.0 (2022) en kebab-case préfixé qti- (qti-assessment-item, qti-choice-interaction), avec attributs en kebab-case (max-choices) et un alignement HTML5. Le modèle conceptuel est le même.
5. Où vit concrètement un paquet QTI ?
Dans un content package dédié (.zip + imsmanifest.xml), dans un Common Cartridge (aux côtés des ressources et liens LTI), ou importé dans la banque de questions d’un LMS. Le support d’import varie selon la plateforme : toujours tester l’import réel.
Chapitre suivant : 11.2 — Common Cartridge — le paquet qui transporte un cours entier, tests QTI et liens LTI compris.