Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A JavaScripthez készült Azure SDK integrációs kódjának tesztelése elengedhetetlen ahhoz, hogy az alkalmazások megfelelően működjenek együtt az Azure-szolgáltatásokkal. Ez az útmutató bemutatja, hogyan tesztelheti hatékonyan az Azure SDK-integrációt a JavaScript-alkalmazásokban egy tesztelési keretrendszerben.
Amikor eldönti, hogy ki szeretné-e másolni a felhőszolgáltatás SDK-hívásait, vagy egy élő szolgáltatást használ tesztelési célokra, fontos figyelembe venni a sebesség, a megbízhatóság és a költségek közötti kompromisszumot. Ez a cikk bemutatja, hogyan használható tesztelési keretrendszer az SDK-integráció teszteléséhez. Az alkalmazáskód beszúr egy dokumentumot a Cosmos DB-be. A tesztkód kiszűkiti az erőforrás-használatot, hogy a felhőbeli erőforrás ne legyen használatban.
A használt keretrendszerek a következők:
- Jest és CommonJs
- Vitest és ESM
- Node.js ESM-et használó tesztfuttató
Előfeltételek
Node.js LTS-t. Az LTS kiadási állapota "hosszú távú támogatás", amely általában garantálja, hogy a kritikus hibákat összesen 30 hónapig kijavítjuk.
A Node.js tesztfuttató a Node.js telepítésének része.
Figyelmeztetés
A Node.js tesztfuttatóhoz megadott minta a kísérleti node:test modult használja, a mock.fn() függvény alkalmazásával. Ne feledje, hogy a Node beépített tesztfuttatója még nem kínál teljes mértékben támogatott szimulálási API-t. Győződjön meg arról, hogy a cél Node verzió támogatja-e a kísérleti API-kat, vagy fontolja meg egy külső gyártótól származó mock könyvtár (vagy stub függvények) használatát.
Felhőszolgáltatások szimulálása
Előnyök:
- Felgyorsítja a tesztcsomagot a hálózati késés megszüntetésével.
- Kiszámítható és szabályozott tesztkörnyezeteket biztosít.
- Egyszerűbben szimulálhat különböző forgatókönyveket és peremes eseteket.
- Csökkenti az élő felhőszolgáltatások használatával kapcsolatos költségeket, különösen a folyamatos integrációs folyamatokban.
hátrányok:
- A makettek a tényleges SDK-ról eltávolodhatnak, ami eltérésekhez vezethet.
- Figyelmen kívül hagyhatja az élő szolgáltatás bizonyos funkcióit vagy viselkedését.
- Kevésbé reális környezet az éles környezethez képest.
Élő szolgáltatás használata
Előnyök:
- Valósághű környezet, amely szorosan tükrözi a termelést?
- Hasznos az integrációs teszteknél, hogy a rendszer különböző részei működjenek együtt?
- Hasznos a hálózat megbízhatóságával, a szolgáltatás rendelkezésre állásával és a tényleges adatkezeléssel kapcsolatos problémák azonosítása?
hátrányok:
- A hálózati hívások miatt lassabb.
- A lehetséges szolgáltatáshasználati költségek miatt drágább.
- Összetett és időigényes az éles környezetnek megfelelő élő szolgáltatási környezet beállítása és karbantartása.
A mockolás és az élő szolgáltatások használata közötti választás a tesztelési stratégiától függ. Az olyan egységtesztek esetében, ahol a sebesség és a vezérlés a legfontosabb, gyakran a gúnyolás a jobb választás. Az olyan integrációs tesztek esetében, ahol a realizmus kulcsfontosságú, az élő szolgáltatás használata pontosabb eredményeket biztosíthat. E megközelítések kiegyensúlyozása segít átfogó tesztelési lefedettséget elérni a költségek kezelése és a teszthatékonyság fenntartása mellett.
Tesztpárok: Makettek, csonkok és hamisak
A teszthelyettesítő bármilyen fajta helyettesítő, amit valós dolgok helyett használnak tesztelési célokra. A választott dupla típus attól függ, hogy mit szeretne lecserélni. A mock kifejezést gyakran kettősként értik, ha a kifejezést alkalmi használatban használják. Ebben a cikkben a kifejezést kifejezetten a Jest tesztelési keretrendszerben használjuk és szemléltetik.
Utánzatok
Mocks (más néven kémek): Helyettesítse a függvényt, és képes legyen ellenőrizni és kémkedni a függvény viselkedését , amikor közvetetten más kód hívja meg.
Az alábbi példákban 2 függvényt használhat:
-
someTestFunction: A tesztelni kívánt függvény. Egy függőséget hív meg,
dependencyFunction, amelyet nem Ön írt, és nem kell tesztelnie. - dependencyFunctionMock: A függőség modellje.
import { mock } from 'node:test';
import assert from 'node:assert';
// ARRANGE
const dependencyFunctionMock = mock.fn();
// ACT
// Mock replaces the call to dependencyFunction with dependencyFunctionMock
const { name } = someTestFunction()
// ASSERT
assert.strictEqual(dependencyFunctionMock.mock.callCount(), 1);
A teszt célja annak biztosítása, hogy egyesTestFunction megfelelően viselkedjen a függőségi kód tényleges invokálása nélkül. A teszt ellenőrzi, hogy a rendszer meghívta-e a függőség mintapéldányát.
Nagy és kis függőségek szimulálása
Ha úgy dönt, hogy egy függőséget modellez, választhatja, hogy a következőhöz hasonló módon modellezi a kívánt elemet:
- Egy vagy két függvény nagyobb függőségből. A Jest részleges álobjektumokat kínál erre a célra.
- Egy kisebb függőség összes függvénye, ahogyan az ebben a cikkben látható példában is látható.
Vázlatok
A csonk célja, hogy egy függvény visszatérési adatait lecserélje, ezzel különböző forgatókönyveket szimuláljon. Egy csonkfüggvény használata lehetőséget ad a kódnak a függvény meghívására, és különböző állapotok fogadására, beleértve a sikeres eredményeket, a hibákat, a kivételeket és a szélsőséges eseteket. Az állapotellenőrzés biztosítja, hogy a kód megfelelően kezelje ezeket a forgatókönyveket.
import { describe, it, beforeEach, mock } from 'node:test';
import assert from 'node:assert';
// ARRANGE
const fakeDatabaseData = {first: 'John', last: 'Jones'};
const dependencyFunctionMock = mock.fn();
dependencyFunctionMock.mock.mockImplementation((arg) => {
return fakeDatabaseData;
});
// ACT
// Mock replaces the call to dependencyFunction with dependencyFunctionMock
const { name } = someTestFunction()
// ASSERT
assert.strictEqual(name, `${fakeDatabaseData.first} ${fakeDatabaseData.last}`);
Az előző teszt célja annak biztosítása, hogy az elvégzett someTestFunction munka megfeleljen a várt eredménynek. Ebben az egyszerű példában a függvény feladata az utó- és családnevek összefűzése. Hamis adatok használatával ismeri a várt eredményt, és ellenőrizheti, hogy a függvény megfelelően végzi-e a munkát.
Hamisítványok
A helyettesítők olyan funkciókat kínálnak, amelyeket általában nem használna éles környezetben, például memóriabeli adatbázis alkalmazása a felhőbeli adatbázis helyett.
// fake-in-mem-db.spec.ts
import { describe, it, beforeEach, afterEach, mock } from 'node:test';
import assert from 'node:assert';
class FakeDatabase {
private data: Record<string, any>;
constructor() {
this.data = {};
}
save(key: string, value: any): void {
this.data[key] = value;
}
get(key: string): any {
return this.data[key];
}
}
// Function to test
function someTestFunction(db: FakeDatabase, key: string, value: any): any {
db.save(key, value);
return db.get(key);
}
describe('In-Mem DB', () => {
let fakeDb: FakeDatabase;
let testKey: string;
let testValue: any;
beforeEach(() => {
fakeDb = new FakeDatabase();
testKey = 'testKey';
testValue = {
first: 'John',
last: 'Jones',
lastUpdated: new Date().toISOString(),
};
});
afterEach(() => {
// Restore all mocks created by node:test’s mock helper.
mock.restoreAll();
});
it('should save and return the correct value', () => {
// Create a spy on the save method using node:test's mock helper.
const saveSpy = mock.method(fakeDb, 'save').mock;
// Call the function under test.
const result = someTestFunction(fakeDb, testKey, testValue);
// Verify state.
assert.deepStrictEqual(result, testValue);
assert.strictEqual(result.first, 'John');
assert.strictEqual(result.last, 'Jones');
assert.strictEqual(result.lastUpdated, testValue.lastUpdated);
// Verify behavior
assert.strictEqual(saveSpy.callCount(), 1);
const calls = saveSpy.calls;
assert.deepStrictEqual(calls[0].arguments, [testKey, testValue]);
});
});
Az előző teszt célja annak biztosítása, hogy someTestFunction megfelelően működjön együtt az adatbázissal. Hamis memóriabeli adatbázis használatával anélkül tesztelheti a függvény logikáját, hogy valódi adatbázisra támaszkodik, így a tesztek gyorsabbak és megbízhatóbbak lesznek.
Forgatókönyv: Dokumentum beszúrása a Cosmos DB-be az Azure SDK használatával
Tegyük fel, hogy rendelkezik egy alkalmazással, amely új dokumentumot kell írnia a Cosmos DB-be , ha az összes információ elküldve és ellenőrizve van. Ha üres űrlapot küld el, vagy az információ nem felel meg a várt formátumnak, az alkalmazásnak nem szabad megadnia az adatokat.
Példaként a Cosmos DB-t használják, de a fogalmak a JavaScripthez készült Azure SDK-k többségére vonatkoznak. A következő függvény rögzíti ezt a funkciót:
// insertDocument.ts
import { Container } from '../data/connect-to-cosmos.js';
import type {
DbDocument,
DbError,
RawInput,
VerificationErrors,
} from '../data/model.js';
import Verify from '../data/verify.js';
export async function insertDocument(
container: Container,
doc: RawInput,
): Promise<DbDocument | DbError | VerificationErrors> {
const isVerified: boolean = Verify.inputVerified(doc);
if (!isVerified) {
return { message: 'Verification failed' } as VerificationErrors;
}
try {
const { resource } = await container.items.create({
id: doc.id,
name: `${doc.first} ${doc.last}`,
});
return resource as DbDocument;
} catch (error: any) {
if (error instanceof Error) {
if ((error as any).code === 409) {
return {
message: 'Insertion failed: Duplicate entry',
code: 409,
} as DbError;
}
return { message: error.message, code: (error as any).code } as DbError;
} else {
return { message: 'An unknown error occurred', code: 500 } as DbError;
}
}
}
Megjegyzés:
A TypeScript-típusok segítenek meghatározni a függvény által használt adattípusokat. Bár nincs szükség TypeScriptre a Jest vagy más JavaScript tesztelési keretrendszerek használatához, ez elengedhetetlen a típusbiztos JavaScript írásához.
Az alkalmazás funkciói a következők:
| Funkció | Leírás |
|---|---|
| insertDocument | Dokumentum beszúrása az adatbázisba. Ezt szeretnénk tesztelni. |
| inputVerified | Ellenőrzi a bemeneti adatokat egy sémán. Biztosítja, hogy az adatok a megfelelő formátumban (például érvényes e-mail-címek, helyesen formázott URL-címek) jelenjenek meg. |
| cosmos.items.create | Az Azure Cosmos DB SDK-függvénye a @azure/cosmos használatával. Ezt szeretnénk kiszúnyolni. Már rendelkezik saját tesztekkel, amelyeket a csomagtulajdonosok tartanak fenn. Ellenőriznünk kell, hogy a Cosmos DB-függvény hívása megtörtént-e, és adatokat ad-e vissza, ha a bejövő adatok ellenőrzésen mentek át. |
Tesztelési keretrendszer függőségének telepítése
Ez a keretrendszer Node.js LTS részeként érhető el.
Csomag konfigurálása teszt futtatásához
Frissítse az package.json alkalmazást egy új szkripttel a forráskódfájlok teszteléséhez. A forráskódfájlok a részleges fájlnév és -bővítmény egyezésével vannak definiálva. A tesztfuttató a tesztfájlok általános elnevezési konvenciója szerint keres fájlokat: <file-name>.spec.[jt]s. Ez a minta azt jelenti, hogy a következő példákhoz hasonló fájlok tesztfájlokként vannak értelmezve, és a tesztfuttató futtatja:
- * .test.js: Például math.test.js
- * .spec.js: Például math.spec.js
- Egy tesztkönyvtárban található fájlok, például tesztek/math.js
Adjon hozzá egy szkriptet a package.json-hoz, amely támogatja a tesztfájlmintát a tesztfuttatóval.
"scripts": {
"test": "node --test --experimental-test-coverage --experimental-test-module-mocks --trace-exit"
}
Egységteszt beállítása az Azure SDK-hoz
Hogyan használhatunk maketteket, csonkokat és hamis elemeket az insertDocument függvény teszteléséhez?
- Mocks: szükségünk van egy makettre a függvény viselkedésének teszteléséhez, például:
- Ha az adatok nem adják át az ellenőrzést, a Cosmos DB függvény hívása csak 1 alkalommal történt
- Ha az adatok nem adják át az ellenőrzést, a Cosmos DB függvény hívása nem történt meg
- Csonkokat:
- A megadott adatok megegyeznek a függvény által visszaadott új dokumentumtal.
A tesztelés során gondolja át a tesztbeállítást, magát a tesztet és az ellenőrzést. A teszt nyelvezet szempontjából ez a funkció a következő kifejezéseket használja:
- Elrendezés: a tesztfeltételek beállítása
- Művelet: a függvény meghívása tesztelésre, más néven a tesztelés alatt álló rendszer vagy a SUT
- Igazolja: ellenőrizze az eredményeket. Az eredmények lehetnek viselkedés vagy állapot.
- A viselkedés a tesztfüggvény funkcióját jelzi, amely ellenőrizhető. Az egyik példa az, hogy néhány függőséget meghívtak.
- Az állapot a függvényből visszaadott adatokat jelzi.
import { describe, it, afterEach, beforeEach, mock } from 'node:test';
import assert from 'node:assert';
describe('boilerplate', () => {
beforeEach(() => {
// Setup required before each test
});
afterEach(() => {
// Cleanup required after each test
});
it('should <do something> if <situation is present>', async () => {
// Arrange
// - set up the test data and the expected result
// Act
// - call the function to test
// Assert
// - check the state: result returned from function
// - check the behavior: dependency function calls
});
});
Amikor a tesztekben mock objektumokat használ, a sablonkódnak a függvény teszteléséhez a függvényben használt mögöttes függőségek, például az Azure ügyfelek könyvtárainak meghívása nélkül kell alkalmaznia a mockolást.
A tesztfájl létrehozása
A modellekkel ellátott tesztfájl, amely egy függőség hívását szimulálja, további beállítással rendelkezik.
A tesztfájlnak több része is van:
-
import: Az import utasítások lehetővé teszik a tesztek használatát vagy megcsúfolását. -
mock: Hozza létre a kívánt alapértelmezett modell viselkedését. Minden teszt szükség szerint módosítható. -
describe: Tesztcsoport család ainsert.tsfájlhoz. -
it: Minden teszt a(z)insert.tsfájlhoz.
A tesztfájl három tesztet tartalmaz a insert.ts fájlhoz, amelyek két érvényesítési típusra oszthatók:
| Érvényesítési típus | Teszt |
|---|---|
Boldog út: should insert document successfully |
A mocked database metódus meghívása megtörtént, és visszaadta a módosított adatokat. |
Hiba elérési útja: should return verification error if input is not verified |
Az adatok érvényesítése sikertelen volt, és hibát adott vissza. |
A hiba útvonala:should return error if db insert fails |
A modellelt adatbázis metódust meghívták, és hibát adott vissza. |
Az alábbi tesztfájl bemutatja, hogyan tesztelheti az insertDocument függvényt .
// insertDocument.test.ts
import { describe, it, beforeEach, mock } from 'node:test';
import assert from 'node:assert';
import { Container } from '../src/data/connect-to-cosmos.js';
import { createTestInputAndResult } from '../src/data/fake-data.js';
import type { DbDocument, DbError, RawInput } from '../src/data/model.js';
import { isDbError, isVerificationErrors } from '../src/data/model.js';
import Verify from '../src/data/verify.js';
import CosmosConnector from '../src/data/connect-to-cosmos.js';
import { insertDocument } from '../src/lib/insert.js';
describe('SDK', () => {
beforeEach(() => {
// Clear all mocks before each test
mock.restoreAll();
});
it('should return verification error if input is not verified', async () => {
const fakeContainer = {
items: {
create: async (_: any) => {
throw new Error('Create method not implemented');
},
},
} as unknown as Container;
const mVerify = mock.method(Verify, 'inputVerified').mock;
mVerify.mockImplementation(() => false);
const mGetUniqueId = mock.method(CosmosConnector, 'getUniqueId').mock;
mGetUniqueId.mockImplementation(() => 'unique-id');
const mContainerCreate = mock.method(fakeContainer.items, 'create').mock;
// Arrange: wrong shape of document on purpose.
const doc = { name: 'test' } as unknown as RawInput;
// Act:
const insertDocumentResult = await insertDocument(fakeContainer, doc);
// Assert - State verification.
if (isVerificationErrors(insertDocumentResult)) {
assert.deepStrictEqual(insertDocumentResult, {
message: 'Verification failed',
});
} else {
throw new Error('Result is not of type VerificationErrors');
}
// Assert - Behavior verification: Verify that create was never called.
assert.strictEqual(mContainerCreate.callCount(), 0);
});
it('should insert document successfully', async () => {
// Arrange: override inputVerified to return true.
const { input, result }: { input: RawInput; result: Partial<DbDocument> } =
createTestInputAndResult();
const fakeContainer = {
items: {
create: async (doc: any) => {
return { resource: result };
},
},
} as unknown as Container;
const mVerify = mock.method(Verify, 'inputVerified').mock;
mVerify.mockImplementation(() => true);
const mContainerCreate = mock.method(
fakeContainer.items as any,
'create',
).mock;
mContainerCreate.mockImplementation(async (doc: any) => {
return { resource: result };
});
// Act:
const receivedResult = await insertDocument(fakeContainer, input);
// Assert - State verification: Ensure the result is as expected.
assert.deepStrictEqual(receivedResult, result);
// Assert - Behavior verification: Ensure create was called once with correct arguments.
assert.strictEqual(mContainerCreate.callCount(), 1);
assert.deepStrictEqual(mContainerCreate.calls[0].arguments[0], {
id: input.id,
name: result.name,
});
});
it('should return error if db insert fails', async () => {
// Arrange: override inputVerified to return true.
const { input, result } = createTestInputAndResult();
const errorMessage: string = 'An unknown error occurred';
const fakeContainer = {
items: {
create: async (doc: any): Promise<any> => {
return Promise.resolve(null);
},
},
} as unknown as Container;
const mVerify = mock.method(Verify, 'inputVerified').mock;
mVerify.mockImplementation(() => true);
const mContainerCreate = mock.method(fakeContainer.items, 'create').mock;
mContainerCreate.mockImplementation(async (doc: any) => {
const mockError: DbError = {
message: errorMessage,
code: 500,
};
throw mockError;
});
// Act:
const insertDocumentResult = await insertDocument(fakeContainer, input);
// // Assert - Ensure create method was called once with the correct arguments.
assert.strictEqual(isDbError(insertDocumentResult), true);
assert.strictEqual(mContainerCreate.callCount(), 1);
assert.deepStrictEqual(mContainerCreate.calls[0].arguments[0], {
id: input.id,
name: result.name,
});
});
});
Hibaelhárítás
A cikkben szereplő kód nagy része a MicrosoftDocs/node-essentials GitHub-adattárból származik. Ha be szeretne szúrni egy Cosmos DB Cloud-erőforrásba, hozza létre az erőforrást ezzel a szkripttel.