From 3dbf97732e170b502cf8f567740c6a9e6732b348 Mon Sep 17 00:00:00 2001 From: didierrc Date: Thu, 21 Mar 2024 00:21:16 +0100 Subject: [PATCH] Added more tests for questionService, especially its generation using Mockups! --- questionservice/jest.config.js | 3 + .../test/question-generator.test.ts | 171 ++++++++++++++++++ questionservice/test/question-service.test.ts | 33 +--- 3 files changed, 182 insertions(+), 25 deletions(-) create mode 100644 questionservice/test/question-generator.test.ts diff --git a/questionservice/jest.config.js b/questionservice/jest.config.js index b413e106..0a8c1398 100644 --- a/questionservice/jest.config.js +++ b/questionservice/jest.config.js @@ -2,4 +2,7 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', + silent: true, // Adding to avoid showing logs from code or errors generated by testing!! + // They are not "suppressing" any error!! Just to have a clean console :) + }; \ No newline at end of file diff --git a/questionservice/test/question-generator.test.ts b/questionservice/test/question-generator.test.ts new file mode 100644 index 00000000..757e2950 --- /dev/null +++ b/questionservice/test/question-generator.test.ts @@ -0,0 +1,171 @@ +import { QuestionModel } from '../src/models/question-model'; +import { getWikidataSparql } from '@entitree/helper'; +import { generateQuestions } from '../src/services/question-generator'; + +// INTO A DIFFERENT FILE TO AVOID MOCKS COLLIDING WITH EACH OTHER + +// Mocking: QuestionModel.aggregate() +// Avoiding flakiness of DB calls +jest.mock("../src/models/question-model") + +// Mocking: getWikidataSparql() +// Avoiding flakiness of API calls +jest.mock("@entitree/helper") + +describe("Question Service - Question Generator", () => { + + beforeEach( () =>{ + jest.clearAllMocks() + }) + + const numberQuestions = 1 + + it("should return 1 question when generator succeeds", async () => { + + // Mock response for fetching MongoDB documents + const mockResponseAggregate: object[] = [{ + questionTemplate: 'What is the Capital of $$$ ?', + question_type: { + name: 'Capitals', + query: `SELECT ?templateLabel ?answerLabel + WHERE { + ?template wdt:P31 wd:$$$; # Entity + wdt:P36 ?answer. # Capital + SERVICE wikibase:label { bd:serviceParam wikibase:language "en,es"} + } + ORDER BY UUID() # Add randomness to the results + LIMIT 10`, + entities: [ + 'Q6256', + 'Q10742', + ], + } + }]; + (QuestionModel.aggregate as jest.Mock).mockReturnValue(mockResponseAggregate) + + // Mock response for Wikidata call + const mockResponseWikidata = [{ + templateLabel: "Peru", + answerLabel: "Lima" + },{ + templateLabel: "Spain", + answerLabel: "Madrid" + },{ + templateLabel: "Russia", + answerLabel: "Moscow" + },{ + templateLabel: "Ucrania", + answerLabel: "Kiev" + }]; + (getWikidataSparql as jest.Mock).mockReturnValue(mockResponseWikidata) + + const response = await generateQuestions(numberQuestions) as object[] + + expect(QuestionModel.aggregate).toHaveBeenCalledWith([ + { $sample: { size: numberQuestions } }, + ]); + expect(response.length).toBe(numberQuestions) + }) + + it("should return 1 question with all correct parameters when generator succeeds", async () => { + + // Mock response for fetching MongoDB documents + const mockResponseAggregate: object[] = [{ + questionTemplate: 'What is the Capital of $$$ ?', + question_type: { + name: 'Capitals', + query: `SELECT ?templateLabel ?answerLabel + WHERE { + ?template wdt:P31 wd:$$$; # Entity + wdt:P36 ?answer. # Capital + SERVICE wikibase:label { bd:serviceParam wikibase:language "en,es"} + } + ORDER BY UUID() # Add randomness to the results + LIMIT 10`, + entities: [ + 'Q6256', + 'Q10742', + ], + } + }]; + (QuestionModel.aggregate as jest.Mock).mockReturnValue(mockResponseAggregate) + + // Mock response for Wikidata call + const mockResponseWikidata = [{ + templateLabel: "Peru", + answerLabel: "Lima" + },{ + templateLabel: "Spain", + answerLabel: "Madrid" + },{ + templateLabel: "Russia", + answerLabel: "Moscow" + },{ + templateLabel: "Ucrania", + answerLabel: "Kiev" + }]; + (getWikidataSparql as jest.Mock).mockReturnValue(mockResponseWikidata) + + const response = await generateQuestions(numberQuestions) as any + + expect(QuestionModel.aggregate).toHaveBeenCalledWith([ + { $sample: { size: numberQuestions } }, + ]); + + expect(response[0]).toHaveProperty("id") // a given id + expect(response[0]).toHaveProperty("question") // the generated question + expect(response[0]).toHaveProperty("answers") // a list of answers + expect(response[0].answers.length).toBe(4) // 4 answers + expect(response[0]).toHaveProperty("correctAnswerId", 1) // a correct answer Id set to 1 + }) + + + it("should return an error if fetching documents from Mongo fails", async () => { + + // Mock response for fetching MongoDB documents + const rejectedMongoResponse = new Error("Mock - Error fetching Questions"); + (QuestionModel.aggregate as jest.Mock).mockRejectedValue(rejectedMongoResponse); + + // Expect that aggregate function rejected with the rejectedMongoResponse + await expect( generateQuestions(numberQuestions) ).rejects.toThrow("Mock - Error fetching Questions"); + + }) + + + it("should return an error if calling wikidata fails", async () => { + + // Mock response for fetching MongoDB documents + const mockResponseAggregate: object[] = [{ + questionTemplate: 'What is the Capital of $$$ ?', + question_type: { + name: 'Capitals', + query: `SELECT ?templateLabel ?answerLabel + WHERE { + ?template wdt:P31 wd:$$$; # Entity + wdt:P36 ?answer. # Capital + SERVICE wikibase:label { bd:serviceParam wikibase:language "en,es"} + } + ORDER BY UUID() # Add randomness to the results + LIMIT 10`, + entities: [ + 'Q6256', + 'Q10742', + ], + } + }]; + (QuestionModel.aggregate as jest.Mock).mockReturnValue(mockResponseAggregate) + + // Mock response for Wikidata call + const rejectedWikidataResponse = new Error("Mock - Error from Wikidata"); + (getWikidataSparql as jest.Mock).mockRejectedValue(rejectedWikidataResponse) + + // Expect that Wikidata call function rejected with the rejectedWikidataResponse + await expect( generateQuestions(numberQuestions) ).rejects.toThrow("Mock - Error from Wikidata"); + + + }) + + + + +}) \ No newline at end of file diff --git a/questionservice/test/question-service.test.ts b/questionservice/test/question-service.test.ts index 4b356b73..3c9a6299 100644 --- a/questionservice/test/question-service.test.ts +++ b/questionservice/test/question-service.test.ts @@ -1,27 +1,8 @@ -//import mongoose from 'mongoose'; -//import { MongoMemoryServer } from 'mongodb-memory-server'; const request = require('supertest'); import app from '../src/app'; import { generateQuestions } from '../src/services/question-generator'; import { generateQuestionsController } from '../src/controllers/question-controller'; -/* NOT USED SO FAR IN TEST... -let mongoServer: MongoMemoryServer; - - // Creating DB connections before ALL tests - beforeAll(async () => { - mongoServer = await MongoMemoryServer.create(); - const mongoUri = mongoServer.getUri(); - process.env.MONGODB_URI = mongoUri; - await mongoose.connect(mongoUri); - }); - - // Closing DB connections after ALL test have been performed - afterAll(async () => { - await mongoose.connection.close(); - await mongoServer.stop(); - }); -*/ describe("Question Service - Health", () => { @@ -79,10 +60,15 @@ describe("Question Service - Erroneous parameters for /questions", () => { }) -// Mocking the generateQuestions(size) function -jest.mock("../src/services/question-generator") +// Mocking the question-generator.ts to test question-controller +// Done to avoid flakiness by calling DB or API +jest.mock('../src/services/question-generator') -describe("Question Service - Question Controller", () => { +describe("Question Service - Question Generation", () => { + + beforeEach( () =>{ + jest.clearAllMocks() + }) it("should return questions when controller succeeds", async () =>{ @@ -134,7 +120,4 @@ describe("Question Service - Question Controller", () => { }) - - - }) \ No newline at end of file