node.js - typeORM'un getCustomRepository'sini nasıl taklit ederim
Yapılandırıcısında getCustomRepository kullanan bir sınıfı birim testi yapmak istiyorum ama bunu kolayca nasıl taklit edeceğimi bir türlü bulamıyorum. İşte sınıfımın kodu
import {getCustomRepository} from 'typeorm';
export class Controller {
private repository: UserRepository;
constructor() {
this.repository = getCustomRepository(UserRepository); //I want to mock this.
}
async init() {
return this.repository.findUser(1);
}
}
ve işte testler
describe('User Tests', () => {
it('should return user', async () => {
//Fake user to be resolved.
const user = new User();
user.id = 2;
//I want to mock getCustomRepository(UserRepository); here
//getCustomRepository = jest.fn().mockResolvedValue(UserRepository); HERE HOW???
//Mocking find user
UserRepository.prototype.findUser = jest.fn().mockResolvedValue(user);
const controller = new Controller();
const result = await controller.init();
expect(result).toBeDefined();
});
});
Not: Depo metodlarını taklit etmek iyi çalışıyor ama aslında getCustomRepository'yi taklit etmek istiyorum çünkü bu, veritabanına bağlanmaya çalışırken harcanan zamanı azaltabilir.
TypeORM'deki getCustomRepository böyle görünüyor
export declare function getCustomRepository<T>(customRepository: ObjectType<T>, connectionName?: string): T;
KullanıcıDeposu.ts
@EntityRepository(User)
export class UserRepository extends Repository<User> {
public async findUser(id: number) {
return 'real user';
}
}
Kullanıcı.ts
@Entity('users')
export class User{
@PrimaryGeneratedColumn()
id: number;
@Column({type: 'varchar', length: 100})
name: string;
}
Yani soru şu: Bunu nasıl taklit edebilirim? Her türlü yardım çok takdir edilecektir.
Cevap #1
Jest kullanarak typeorm modülünü, getCustomRepository fonksiyonunu ve döndürülen değerini taklit etmek için jest.mock(moduleName, factory, options) kullanabilirsiniz.
Örn.
controller.ts:
import { getCustomRepository } from 'typeorm';
import { UserRepository } from './userRepo';
export class Controller {
private repository: UserRepository;
constructor() {
this.repository = getCustomRepository(UserRepository);
}
async init() {
return this.repository.findUser(1);
}
}
userRepo.ts:
export class UserRepository {
public async findUser(id: number) {
return 'real user';
}
}
controller.test.ts:
import { Controller } from './controller';
import { getCustomRepository } from 'typeorm';
import { mocked } from 'ts-jest/utils';
import { UserRepository } from './userRepo';
jest.mock('typeorm', () => ({ getCustomRepository: jest.fn() }));
describe('61693597', () => {
it('should pass', async () => {
const userRepo = { findUser: jest.fn().mockResolvedValueOnce('fake user') };
mocked(getCustomRepository).mockReturnValueOnce(userRepo);
const controller = new Controller();
const actual = await controller.init();
expect(actual).toBe('fake user');
expect(getCustomRepository).toBeCalledWith(UserRepository);
expect(userRepo.findUser).toBeCalledWith(1);
});
});
kapsam raporu ile birim testi sonuçları:
PASS stackoverflow/61693597/controller.test.ts (13.53s)
61693597
✓ should pass (9ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 92.31 | 100 | 80 | 90.91 |
controller.ts | 100 | 100 | 100 | 100 |
userRepo.ts | 80 | 100 | 50 | 75 | 3
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 15.596s
kaynak kodu: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61693597
Cevap #2
Daha önce bir yorumda bahsedildiği gibi, @slideshowp2'nin cevabını çoğaltmayı denedim. ts-jest'ten gelen mocked() yardımcı işlevi 'mockResolvedValueOnce' değerini tanımsız olarak döndürüyordu.
Bunu çözmek için, onu birkaç adıma ayırmak zorunda kaldım:
- daha derinlemesine taklit yapmak için bir bağımlılık olarak sinon ekleyin
- (çok önemli)
getCustomRepositoryfonksiyonu için bir kapsayıcı oluştur
Sarmalayıcı olmadan, özelliğin salt okunur olması nedeniyle dönüş değerini taklit etmek neredeyse imkansızdır. Şu gibi bir şey yapmak yeterli olmalıdır:
c: Connection;
public async getCustomRepository<T>(type: ObjectType<T>): Promise<T> {
if (!this.c || !this.c.isConnected) {
this.c = await this.getConnection();
}
return await this.c.getCustomRepository(type);
}
Bunu yaptıktan sonra, getCustomRepository fonksiyonunu şu şekilde taklit etmeyi başardım:
describe('Unit tests', () => {
let sandbox: sinon.SinonSandbox;
let useCase: FindNodeUseCase;
let repositoryStub: sinon.SinonStub;
let nodeTreeRepo: NodeTreeRepository;
beforeEach(() => {
sandbox = sinon.createSandbox();
useCase = new FindNodeUseCase();
const mockNode = new NodeTree();
mockNode.idNode = 1;
mockNode.level = 1;
nodeTreeRepo = new NodeTreeRepository()
nodeTreeRepo.findOne = jest.fn().mockResolvedValue(mockNode)
nodeTreeRepo.findByIdAndLanguage = jest.fn().mockReturnValue(
[
[{ idNode: 1, level: 2, names: [{ idNode: 1, nodeName:"Sales" }] }],
1
]
);
repositoryStub = sandbox.stub(useCase.databaseManager, 'getCustomRepository').resolves(nodeTreeRepo)
})
afterEach(() => {
sandbox.restore();
})
