node.js - jest-mock ile prisma nasıl taklit edilir


Veritabanımla etkileşim kurmak için Prisma kullanıyorum ve findMany çağrısını taklit etmek için jest-mock kullanmak istiyorum. https://jestjs.io/docs/jest-object#jestmockedtitem-t-deep--false

brands.test.ts

import { PrismaService } from "@services/mysql.service";
import { mocked } from "jest-mock";
import faker from "@faker-js/faker";
import { GetBrands } from "./brand";
jest.mock("@services/mysql.service");

/**
 * @group unit
 */

describe("Brand", () => {
    afterAll(async () => {});

    const mockedPrismaService = mocked(PrismaService, true);
    it("should get a list of brands", async () => {
        const mockedData = [
            {
                id: faker.datatype.uuid(),
                name: faker.datatype.string(),
                image: {
                    source: "some_source",
                    dtype: "some_dtype",
                },
            },
        ];

        //@ts-ignore - because of relational data mockedData.image
        mockedPrismaService.brand.findMany.mockResolvedValueOnce(mockedData);

        const [response, error] = await GetBrands();

        console.log(response, error);
    });
});

mysql.service.ts

import mysql from "mysql2/promise";
import { Config } from "@config";
import { PrismaClient, Prisma } from "@prisma/client";

export const MySQLEscape = mysql.escape;
export const MySQLPreparedStatement = mysql.format;

export const PrismaService = new PrismaClient({});
export const PrismaHelper = Prisma;

Ancak bu testi çalıştırdığımda aşağıdaki hatayı alıyorum.

TypeError: Cannot read properties of undefined (reading 'brand')

Cevap #1

Fabrika Sahte

Bir seçenek, istemcinizi taklit ederken fabrika yaklaşımını kullanma seçeneğidir.

jest.mock("@services/mysql.service", () => ({
    PrismaService: {
        brand: {
            findMany: jest.fn(() => { })
        }
    },
}));

O zaman testiniz içinde, findMany fonksiyonunu test verilerinizi döndürecek şekilde sahteleyebilir, ardından test edilen fonksiyonu çağırabilirsiniz.

const mockedData = [...];
PrismaService.brand.findMany.mockResolvedValueOnce(mockedData);
const result = await GetBrands();

Biraz zahmetli, ama işe yarıyor.

Örneğimde, GetBrands yöntemini şu şekilde uyguladığımı unutmayın:

import { PrismaService } from "@services/mysql.service"

export const GetBrands = async () => {
    const data = await PrismaService.brand.findMany();
    return data;
}

Senin örneğin

Örneğinizde otomatik taklit (mocking) kullanıyorsunuz ve ben buna pek aşina değilim, bu yüzden nasıl çalıştıracağımı bilmiyorum.

Hatanın oluşmasına sebep olan şey gibi görünen, PrismaService'in burada içe aktarıldığında tanımsız olması:

import { PrismaService } from "@services/mysql.service";

Ve sonra mocked fonksiyonunu tanımsız bir parametre ile çağırmak tanımsız döndürür:

const mockedPrismaService = mocked(undefined, true); // returns undefined

Ve sonunda, aşağıdakini çağırmak hatayı ortaya çıkarıyor:

mockedPrismaService.brand.findMany.mockResolvedValueOnce(mockedData);
// TypeError: Cannot read properties of undefined (reading 'brand')

Böyle bir şeyin aradığınız şey olacağını düşünürdüm, ama bu bir hata veriyor:

jest.mock("@services/mysql.service", () => ({
    PrismaService: mocked(PrismaService, true)
}));
//    6 |
//    7 | jest.mock("@services/mysql.service", () => ({
//>   8 |     PrismaService: mocked(PrismaClient, true)
//      |                    ^
//    9 | }));

Belgeleri inceleyin

Prismas'ın birim testi ile ilgili dokümantasyonunu gözden geçirmek faydalı olabilir, çünkü birkaç oldukça farklı yaklaşım öneriyorlar.

Cevap #2

deneyimimden bir örnek, brands.test.ts içinde:

import { PrismaService } from "@services/mysql.service";
..
jest.spyOn(PrismaService.brand , 'findMany').mockResolvedValueOnce(mockedData)

İlgili makaleler