Merhaba,
Bu yazıda NestJS ile Unit Test kullanımından bahsedeceğim.
İlk olarak bir NestJS projesi oluşturuyoruz:
nest new nest-unit-test-sample
Projede ürün ekleme, listeleme ve silme şeklinde CRUD işlemleri yapacağız. Veritabanı olarak MySQL kullanacağız. API hazır olduktan sonra da unit testleri yazacağız. MySQL için gerekli paketleri kuralım:
npm i @nestjs/typeorm typeorm mysql
Local ortamımızda nest_unit_test_sample_db adında bir veritabanı oluşturup içerisine products tablosu ekliyoruz. Bu tabloya da id, name, description ve price sütunları ekliyoruz.
app.module.ts dosyasını açarak TypeOrm modülünü dahil ediyoruz ve veritabanı bilgilerimizi yazıyoruz:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ProductsModule } from './products/products.module';
@Module({
imports: [TypeOrmModule.forRoot({
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "12345678",
"database": "nest_unit_test_sample_db",
"synchronize": false,
"logging": true,
"entities": ["dist/**/*.entity.js"]
}), ProductsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
products modülü oluşturuyoruz:
nest g module products
Veritabanındaki products tablosuna karşılık gelecek şekilde src/products altında products.entity.ts adında bir entity oluşturuyoruz:
import { PrimaryGeneratedColumn, Column, Entity } from 'typeorm';
@Entity('products')
export class ProductsEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
price: string;
}
src/products altına dto klasörü oluşturuyoruz. Onun altına da create-product.dto.ts dosyası oluşturuyoruz:
export class CreateProductDTO {
id: number;
name: string;
description: string;
price: string;
}
products servisi oluşturuyoruz:
nest g service products
products.service.ts:
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ProductsEntity } from './products.entity';
import { CreateProductDTO } from './dto/create-product.dto';
@Injectable()
export class ProductsService {
constructor(
@InjectRepository(ProductsEntity)
private productsRepository: Repository<ProductsEntity>,
) {}
public async createProduct(
createProductDto: CreateProductDTO,
): Promise<ProductsEntity> {
return await this.productsRepository.save(createProductDto);
}
public async getProducts(): Promise<ProductsEntity[]> {
return await this.productsRepository.find();
}
public async deleteProduct(productId: number): Promise<void> {
await this.productsRepository.delete(productId);
}
}
products controller dosyasını oluşturuyoruz:
nest g controller products --no-spec
products.controller.ts:
import {
Controller,
Post,
Body,
Get,
Param,
Delete,
} from '@nestjs/common';
import { ProductsService } from './products.service';
import { CreateProductDTO } from './dto/create-product.dto';
import { ProductsEntity } from './products.entity';
@Controller('products')
export class ProductsController {
constructor(private productsService: ProductsService) {}
@Post('create')
public async createProduct(
@Body() createProductDto: CreateProductDTO,
): Promise<ProductsEntity> {
const product = await this.productsService.createProduct(createProductDto);
return product;
}
@Get('all')
public async getProducts(): Promise<ProductsEntity[]> {
const products = await this.productsService.getProducts();
return products;
}
@Delete('/delete/:productId')
public async deleteProduct(@Param('productId') productId: number) {
const deletedProduct = await this.productsService.deleteProduct(productId);
return deletedProduct;
}
}
products.module.ts dosyasını açarak gerekli düzenlemeleri yapıyoruz:
import { Module } from '@nestjs/common';
import { ProductsService } from './products.service';
import { ProductsController } from './products.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProductsEntity } from './products.entity';
@Module({
imports: [TypeOrmModule.forFeature([ProductsEntity])],
providers: [ProductsService],
controllers: [ProductsController]
})
export class ProductsModule {}
API hazır. Projeyi npm run start komutu ile ayağa kaldırarak Postman üzerinden testleri yapabilirsiniz. Şimdi işin unit test kısmına gelelim.
products.service.spec.ts dosyasını açarak şu şekilde bir kodlama yapıyoruz:
import { Test, TestingModule } from '@nestjs/testing';
import { ProductsService } from './products.service';
import { ProductsEntity } from './products.entity';
import { getRepositoryToken } from '@nestjs/typeorm';
describe('ProductService', () => {
let productService;
let productRepository;
const mockProductRepository = () => ({
save: jest.fn(),
find: jest.fn(),
delete: jest.fn(),
});
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ProductsService,
{
provide: getRepositoryToken(ProductsEntity),
useFactory: mockProductRepository,
},
],
}).compile();
productService = await module.get<ProductsService>(ProductsService);
productRepository = await module.get(getRepositoryToken(ProductsEntity));
});
describe('createProduct', () => {
it('should save a product in the database', async () => {
productRepository.save.mockResolvedValue('someProduct');
expect(productRepository.save).not.toHaveBeenCalled();
const createProductDto = {
name: 'sample name',
description: 'sample description',
price: 'sample price',
};
const result = await productService.createProduct(createProductDto);
expect(productRepository.save).toHaveBeenCalledWith(
createProductDto,
);
expect(result).toEqual('someProduct');
});
});
describe('getProducts', () => {
it('should get all products', async () => {
productRepository.find.mockResolvedValue('someProducts');
expect(productRepository.find).not.toHaveBeenCalled();
const result = await productService.getProducts();
expect(productRepository.find).toHaveBeenCalled();
expect(result).toEqual('someProducts');
});
});
describe('deleteProduct', () => {
it('should delete product', async () => {
productRepository.delete.mockResolvedValue(1);
expect(productRepository.delete).not.toHaveBeenCalled();
await productService.deleteProduct(1);
expect(productRepository.delete).toHaveBeenCalledWith(1);
});
});
});
Burada yaptığımız işlemler;
- beforeEach kısmında her test öncesi çalıştırılacak kodları yazdık. Burada servis ve repository için mock (sahte) tanımlamaları yaptık.
- createProduct şeklinde bir test yazdık. Burada örnek bir product verisi tanımlayıp servis üzerindeki ürün oluşturma fonksiyonumuzu çağırdık. Servisten gelen değerle elimizdeki örnek veriyi karşılaştırdık.
- getProducts şeklinde bir test yazdık. Burada servis üzerindeki ürünleri listeleme fonksiyonumuzu çağırdık. Repository üzerindeki find fonksiyonunu da çağırdık ve servisten gelen değerle karşılaştırdık.
- deleteProduct şeklinde bir test yazdık. Burada servis üzerindeki ürün silme fonksiyonumuzu çağırdık. Repository üzerindeki delete fonksiyonunu da çağırdık ve servisten gelen değerle karşılaştırdık.
Testlerimizi çalıştırıyoruz:
npm run test
Konsoldaki çıktımız şu şekilde oluyor:
Projenin kaynak kodlarına buradan ulaşabilirsiniz.
Umarım yararlı olmuştur.
İyi çalışmalar.
Yorumlar Henüz yorum yapılmamış
Yeni Yorum