test-assessment-generation.js•19.2 kB
/**
* Assessment Generation System Tests
* @description Comprehensive test suite for assessment generation components
* @version 5.0.0-alpha
*/
import {
AssessmentEngine,
FlashcardGenerator,
QuizGenerator,
AnswerRandomizer,
ComplexityAdapter,
QualityValidator,
createAssessmentEngine,
generateComprehensiveAssessment
} from '../../src/content-generation/index.js';
// Test data
const mockTopicAnalysis = {
subject: 'física',
gradeLevel: 'medio',
complexity: 'medium',
keywords: ['força', 'movimento', 'energia', 'velocidade'],
concepts: ['dinâmica', 'cinemática', 'energia cinética', 'leis de Newton'],
learningObjectives: [
'Compreender as leis de Newton',
'Aplicar conceitos de força e movimento',
'Resolver problemas de dinâmica'
]
};
const mockContent = {
metadata: {
topic: 'Leis de Newton e Dinâmica',
subject: 'física',
gradeLevel: 'medio',
complexity: 'medium'
},
components: {
introduction: {
type: 'introduction',
title: 'Introdução à Dinâmica',
content: 'A dinâmica é o ramo da física que estuda as causas do movimento dos corpos.'
},
explanation: {
type: 'explanation',
title: 'Leis de Newton',
content: 'Sir Isaac Newton formulou três leis fundamentais que descrevem a relação entre as forças que atuam sobre um corpo e seu movimento. A primeira lei estabelece o conceito de inércia, a segunda relaciona força com aceleração, e a terceira trata da ação e reação.'
},
examples: {
type: 'examples',
title: 'Exemplos Práticos',
examples: [
'Um carro freando demonstra a primeira lei de Newton',
'Empurrar um objeto aplica a segunda lei de Newton',
'Caminhar ilustra a terceira lei de Newton'
]
},
summary: {
type: 'summary',
title: 'Resumo',
content: 'As leis de Newton são fundamentais para compreender o movimento e as forças na física clássica.'
}
}
};
// Test suite
export async function runAssessmentGenerationTests() {
console.log('\n🧪 Starting Assessment Generation System Tests');
console.log('='.repeat(60));
const results = {
total: 0,
passed: 0,
failed: 0,
errors: []
};
const tests = [
// Core component tests
{ name: 'FlashcardGenerator - Basic Generation', test: testFlashcardGeneratorBasic },
{ name: 'FlashcardGenerator - Type Variety', test: testFlashcardGeneratorTypeVariety },
{ name: 'FlashcardGenerator - Content Quality', test: testFlashcardGeneratorQuality },
{ name: 'QuizGenerator - Basic Generation', test: testQuizGeneratorBasic },
{ name: 'QuizGenerator - Question Types', test: testQuizGeneratorTypes },
{ name: 'QuizGenerator - Difficulty Balance', test: testQuizGeneratorDifficulty },
{ name: 'AnswerRandomizer - Multiple Choice', test: testAnswerRandomizerMC },
{ name: 'AnswerRandomizer - Position Distribution', test: testAnswerRandomizerDistribution },
{ name: 'AnswerRandomizer - Matching Questions', test: testAnswerRandomizerMatching },
{ name: 'ComplexityAdapter - Grade Level Adaptation', test: testComplexityAdapterGradeLevels },
{ name: 'ComplexityAdapter - Vocabulary Adaptation', test: testComplexityAdapterVocabulary },
{ name: 'ComplexityAdapter - Question Filtering', test: testComplexityAdapterFiltering },
{ name: 'QualityValidator - Flashcard Validation', test: testQualityValidatorFlashcards },
{ name: 'QualityValidator - Quiz Validation', test: testQualityValidatorQuiz },
{ name: 'QualityValidator - Auto Correction', test: testQualityValidatorCorrection },
{ name: 'AssessmentEngine - Complete Generation', test: testAssessmentEngineComplete },
{ name: 'AssessmentEngine - Subject Enhancement', test: testAssessmentEngineSubjectEnhancement },
{ name: 'AssessmentEngine - Integration Pipeline', test: testAssessmentEngineIntegration },
// Factory and convenience function tests
{ name: 'Factory Functions - Assessment Creation', test: testFactoryFunctions },
{ name: 'Convenience Functions - Comprehensive Assessment', test: testConvenienceFunctions },
// Integration tests
{ name: 'Integration - Full Assessment Pipeline', test: testFullAssessmentPipeline },
{ name: 'Integration - Error Handling', test: testErrorHandling },
{ name: 'Integration - Performance', test: testPerformance }
];
for (const { name, test } of tests) {
results.total++;
try {
console.log(`\n⏳ Running: ${name}`);
const startTime = Date.now();
await test();
const duration = Date.now() - startTime;
console.log(`✅ PASSED: ${name} (${duration}ms)`);
results.passed++;
} catch (error) {
console.log(`❌ FAILED: ${name}`);
console.log(` Error: ${error.message}`);
results.failed++;
results.errors.push({ test: name, error: error.message });
}
}
// Print test summary
console.log('\n' + '='.repeat(60));
console.log('📊 Assessment Generation Test Results');
console.log('='.repeat(60));
console.log(`Total Tests: ${results.total}`);
console.log(`✅ Passed: ${results.passed}`);
console.log(`❌ Failed: ${results.failed}`);
console.log(`📈 Success Rate: ${((results.passed / results.total) * 100).toFixed(1)}%`);
if (results.errors.length > 0) {
console.log('\n❌ Failed Tests:');
results.errors.forEach(({ test, error }) => {
console.log(` - ${test}: ${error}`);
});
}
return results;
}
// FlashcardGenerator Tests
async function testFlashcardGeneratorBasic() {
const generator = new FlashcardGenerator();
const flashcards = await generator.generateFlashcards(mockContent, mockTopicAnalysis);
if (!Array.isArray(flashcards)) {
throw new Error('Flashcards should be an array');
}
if (flashcards.length < 5) {
throw new Error('Should generate at least 5 flashcards');
}
const firstCard = flashcards[0];
if (!firstCard.front || !firstCard.back || !firstCard.type) {
throw new Error('Flashcards should have front, back, and type properties');
}
}
async function testFlashcardGeneratorTypeVariety() {
const generator = new FlashcardGenerator();
const flashcards = await generator.generateFlashcards(mockContent, mockTopicAnalysis);
const types = new Set(flashcards.map(card => card.type));
if (types.size < 2) {
throw new Error('Should generate multiple flashcard types');
}
}
async function testFlashcardGeneratorQuality() {
const generator = new FlashcardGenerator();
const flashcards = await generator.generateFlashcards(mockContent, mockTopicAnalysis);
// Check content quality
for (const card of flashcards) {
if (card.front.length < 5 || card.back.length < 10) {
throw new Error('Flashcard content too short');
}
if (!card.difficulty || !card.tags) {
throw new Error('Flashcards should have difficulty and tags');
}
}
// Check statistics
const stats = generator.calculateStatistics(flashcards);
if (stats.qualityScore < 70) {
throw new Error('Flashcard quality score too low');
}
}
// QuizGenerator Tests
async function testQuizGeneratorBasic() {
const generator = new QuizGenerator();
const quiz = await generator.generateQuiz(mockContent, mockTopicAnalysis);
if (!quiz.questions || !Array.isArray(quiz.questions)) {
throw new Error('Quiz should have questions array');
}
if (quiz.questions.length < 3) {
throw new Error('Should generate at least 3 questions');
}
if (!quiz.metadata || !quiz.instructions) {
throw new Error('Quiz should have metadata and instructions');
}
}
async function testQuizGeneratorTypes() {
const generator = new QuizGenerator();
const quiz = await generator.generateQuiz(mockContent, mockTopicAnalysis);
const types = new Set(quiz.questions.map(q => q.type));
if (types.size < 2) {
throw new Error('Should generate multiple question types');
}
// Check specific question types
const mcQuestions = quiz.questions.filter(q => q.type === 'multiple_choice');
if (mcQuestions.length === 0) {
throw new Error('Should generate multiple choice questions');
}
const mcQuestion = mcQuestions[0];
if (!mcQuestion.options || mcQuestion.options.length < 2) {
throw new Error('Multiple choice questions should have options');
}
}
async function testQuizGeneratorDifficulty() {
const generator = new QuizGenerator();
const quiz = await generator.generateQuiz(mockContent, mockTopicAnalysis);
const difficulties = new Set(quiz.questions.map(q => q.difficulty));
if (difficulties.size < 2) {
throw new Error('Should generate questions with varied difficulty');
}
}
// AnswerRandomizer Tests
async function testAnswerRandomizerMC() {
const randomizer = new AnswerRandomizer();
const question = {
type: 'multiple_choice',
question: 'Test question?',
options: ['A', 'B', 'C', 'D'],
correct: 0
};
const randomized = await randomizer.randomizeQuestion(question);
if (!randomized.randomization) {
throw new Error('Randomized question should have randomization metadata');
}
if (randomized.options[randomized.correct] !== 'A') {
throw new Error('Correct answer should still be correct after randomization');
}
}
async function testAnswerRandomizerDistribution() {
const randomizer = new AnswerRandomizer();
// Generate multiple randomized questions
const questions = [];
for (let i = 0; i < 20; i++) {
const question = {
type: 'multiple_choice',
question: `Test question ${i}?`,
options: ['A', 'B', 'C', 'D'],
correct: 0
};
questions.push(question);
}
const assessment = { quiz: { questions } };
const randomized = await randomizer.randomizeAssessment(assessment);
// Check position distribution
const positions = randomized.quiz.questions.map(q => q.correct);
const uniquePositions = new Set(positions);
if (uniquePositions.size < 2) {
throw new Error('Answer positions should be distributed');
}
}
async function testAnswerRandomizerMatching() {
const randomizer = new AnswerRandomizer();
const question = {
type: 'matching',
leftColumn: ['A', 'B', 'C'],
rightColumn: ['1', '2', '3'],
correctPairs: [
{ left: 0, right: 0 },
{ left: 1, right: 1 },
{ left: 2, right: 2 }
]
};
const randomized = await randomizer.randomizeQuestion(question);
if (!randomized.randomization) {
throw new Error('Matching question should have randomization metadata');
}
// Verify correct pairs are still valid
for (const pair of randomized.correctPairs) {
const leftItem = randomized.leftColumn[pair.left];
const rightItem = randomized.rightColumn[pair.right];
// Basic validation that pairing makes sense
if (!leftItem || !rightItem) {
throw new Error('Invalid correct pair after randomization');
}
}
}
// ComplexityAdapter Tests
async function testComplexityAdapterGradeLevels() {
const adapter = new ComplexityAdapter();
const assessment = {
flashcards: [
{ front: 'Complex terminology test', back: 'Advanced explanation', difficulty: 'hard' }
],
quiz: {
questions: [
{
type: 'multiple_choice',
question: 'Complex question with advanced terminology?',
options: ['A', 'B', 'C', 'D'],
correct: 0,
difficulty: 'hard'
}
]
}
};
const adapted = await adapter.adaptAssessment(assessment, 'fundamental-1');
if (!adapted.metadata || adapted.metadata.adaptedGradeLevel !== 'fundamental-1') {
throw new Error('Assessment should be adapted for fundamental-1 level');
}
}
async function testComplexityAdapterVocabulary() {
const adapter = new ComplexityAdapter();
const text = 'Compreender o conceito fundamental é significativo para a metodologia.';
const simplified = adapter.adaptVocabulary(text, 'simple');
if (simplified.includes('compreender') || simplified.includes('metodologia')) {
throw new Error('Complex vocabulary should be simplified');
}
}
async function testComplexityAdapterFiltering() {
const adapter = new ComplexityAdapter();
const questions = [
{ type: 'multiple_choice', category: 'knowledge', difficulty: 'easy' },
{ type: 'short_answer', category: 'evaluation', difficulty: 'hard' }
];
const adapted = await adapter.adaptQuestions(questions, 'fundamental-1');
// Should filter out evaluation questions for fundamental level
const evaluationQuestions = adapted.filter(q => q.category === 'evaluation');
if (evaluationQuestions.length > 0) {
throw new Error('High-level questions should be filtered for lower grade levels');
}
}
// QualityValidator Tests
async function testQualityValidatorFlashcards() {
const validator = new QualityValidator();
const flashcards = [
{ front: 'What is X?', back: 'X is...', type: 'concept', difficulty: 'easy' },
{ front: 'Example of Y?', back: 'Y examples include...', type: 'example', difficulty: 'medium' }
];
const validation = await validator.validateFlashcards(flashcards);
if (validation.score < 0 || validation.score > 100) {
throw new Error('Validation score should be between 0-100');
}
if (!Array.isArray(validation.issues)) {
throw new Error('Validation should return issues array');
}
}
async function testQualityValidatorQuiz() {
const validator = new QualityValidator();
const quiz = {
questions: [
{
type: 'multiple_choice',
question: 'Test question?',
options: ['A', 'B', 'C', 'D'],
correct: 0,
difficulty: 'medium'
}
]
};
const validation = await validator.validateQuiz(quiz);
if (validation.score < 0 || validation.score > 100) {
throw new Error('Quiz validation score should be between 0-100');
}
}
async function testQualityValidatorCorrection() {
const validator = new QualityValidator({ enableAutoCorrection: true });
// Create assessment with insufficient content
const poorAssessment = {
flashcards: [
{ front: 'Q1', back: 'A1', type: 'concept', difficulty: 'easy' }
], // Too few flashcards
quiz: {
questions: [
{
type: 'multiple_choice',
question: 'Q?',
options: ['A', 'B'],
correct: 0,
difficulty: 'medium'
}
]
}
};
const validated = await validator.validateAssessment(poorAssessment);
if (!validated.validation) {
throw new Error('Validated assessment should have validation metadata');
}
// Should have more flashcards after correction
if (validated.flashcards.length <= poorAssessment.flashcards.length) {
throw new Error('Auto-correction should add content when insufficient');
}
}
// AssessmentEngine Tests
async function testAssessmentEngineComplete() {
const engine = new AssessmentEngine();
const assessment = await engine.generateAssessment(mockContent, mockTopicAnalysis);
if (!assessment.flashcards || !assessment.quiz) {
throw new Error('Assessment should have flashcards and quiz');
}
if (!assessment.metadata) {
throw new Error('Assessment should have metadata');
}
if (assessment.flashcards.length === 0 || assessment.quiz.questions.length === 0) {
throw new Error('Assessment should have content');
}
}
async function testAssessmentEngineSubjectEnhancement() {
const engine = new AssessmentEngine();
const assessment = await engine.generateSubjectSpecificAssessment(
mockContent,
mockTopicAnalysis,
'physics'
);
if (!assessment.metadata.subjectEnhancements) {
throw new Error('Physics assessment should have subject enhancements');
}
}
async function testAssessmentEngineIntegration() {
const engine = new AssessmentEngine();
// Test the full pipeline
const assessment = await engine.generateAssessment(mockContent, mockTopicAnalysis, {
includeFlashcards: true,
includeQuiz: true,
gradeLevel: 'medio'
});
// Check randomization was applied
if (!assessment.analytics || !assessment.analytics.randomizationApplied) {
throw new Error('Assessment should show randomization was applied');
}
// Check quality validation
if (!assessment.validation || !assessment.validation.qualityScore) {
throw new Error('Assessment should have quality validation');
}
}
// Factory Function Tests
async function testFactoryFunctions() {
const engine = await createAssessmentEngine({ minFlashcards: 5 });
if (!engine || typeof engine.generateAssessment !== 'function') {
throw new Error('Factory should create functional AssessmentEngine');
}
}
async function testConvenienceFunctions() {
const assessment = await generateComprehensiveAssessment(
mockContent,
mockTopicAnalysis,
{ includeFlashcards: true }
);
if (!assessment.flashcards || !assessment.quiz) {
throw new Error('Convenience function should generate complete assessment');
}
}
// Integration Tests
async function testFullAssessmentPipeline() {
// Test the complete pipeline from content to validated assessment
const engine = new AssessmentEngine({
enableRandomization: true,
qualityThreshold: 0.7
});
const assessment = await engine.generateAssessment(mockContent, mockTopicAnalysis, {
includeFlashcards: true,
includeQuiz: true,
gradeLevel: 'medio'
});
// Verify all pipeline steps were executed
if (!assessment.flashcards || assessment.flashcards.length === 0) {
throw new Error('Pipeline should generate flashcards');
}
if (!assessment.quiz || !assessment.quiz.questions || assessment.quiz.questions.length === 0) {
throw new Error('Pipeline should generate quiz questions');
}
if (!assessment.validation || !assessment.validation.qualityScore) {
throw new Error('Pipeline should include quality validation');
}
if (!assessment.analytics || !assessment.analytics.randomizationApplied) {
throw new Error('Pipeline should include randomization');
}
}
async function testErrorHandling() {
const engine = new AssessmentEngine();
try {
// Test with invalid input
await engine.generateAssessment(null, null);
throw new Error('Should throw error with invalid input');
} catch (error) {
if (!error.message.includes('failed')) {
throw new Error('Should throw descriptive error message');
}
}
}
async function testPerformance() {
const engine = new AssessmentEngine();
const startTime = Date.now();
const assessment = await engine.generateAssessment(mockContent, mockTopicAnalysis);
const duration = Date.now() - startTime;
if (duration > 5000) { // 5 seconds
throw new Error(`Assessment generation too slow: ${duration}ms`);
}
if (!assessment.flashcards || !assessment.quiz) {
throw new Error('Performance test should still generate complete assessment');
}
}
// Export test runner for integration with main test suite
export { runAssessmentGenerationTests };