TypeORM অ্যাপ্লিকেশন টেস্টিং এবং ডিবাগিং
TypeORM হল একটি শক্তিশালী ORM (Object-Relational Mapping) লাইব্রেরি যা TypeScript এবং JavaScript ব্যবহারকারীদের ডেটাবেসের সাথে সহজভাবে কাজ করতে সহায়তা করে। অ্যাপ্লিকেশন ডেভেলপমেন্টের পর Testing এবং Debugging একটি অপরিহার্য প্রক্রিয়া, যা নিশ্চিত করে যে অ্যাপ্লিকেশনটি সঠিকভাবে কাজ করছে এবং কোন ভুল বা ত্রুটি ঘটছে না। TypeORM ব্যবহার করার সময় টেস্টিং এবং ডিবাগিংয়ের সঠিক পদ্ধতি অনুসরণ করা গুরুত্বপূর্ণ, কারণ এটি কোডের বাগ নির্ধারণ এবং সঠিক ফলাফল প্রদান নিশ্চিত করে।
এই গাইডে TypeORM অ্যাপ্লিকেশনের Testing এবং Debugging পদ্ধতি নিয়ে আলোচনা করা হবে।
১. TypeORM অ্যাপ্লিকেশন টেস্টিং
টেস্টিং হল কোডের সঠিকতা যাচাই করার প্রক্রিয়া। TypeORM অ্যাপ্লিকেশন টেস্টিং মূলত দুটি প্রধান পদ্ধতিতে করা যায়: Unit Testing এবং Integration Testing।
Unit Testing
Unit Testing এমন একটি পদ্ধতি যেখানে একেকটি ফাংশন বা ক্লাসের কার্যকারিতা এককভাবে পরীক্ষা করা হয়।
Integration Testing
Integration Testing হল বিভিন্ন মডিউল বা কম্পোনেন্টের একসাথে কাজ করার জন্য টেস্টিং। এতে ডাটাবেস ইন্টারঅ্যাকশন সহ অনেক ফিচার টেস্ট করা হয়।
TypeORM এর টেস্টিং পদ্ধতি
- Test Database Setup: আপনি যখন TypeORM টেস্ট করবেন, তখন সাধারণত in-memory database ব্যবহার করা হয়, যাতে টেস্ট রান করার সময় ডাটাবেস পরিবর্তন না হয়।
- Test Environment Configuration: টেস্টের জন্য আলাদা কনফিগারেশন তৈরি করতে হবে, যাতে প্রোডাকশন ডাটাবেসের সাথে কনফ্লিক্ট না হয়।
উদাহরণ: Unit Test তৈরি করা
TypeORM অ্যাপ্লিকেশন টেস্ট করার জন্য Jest বা Mocha ব্যবহার করা যায়। এখানে Jest এর সাহায্যে টেস্ট করার উদাহরণ দেওয়া হচ্ছে।
npm install --save-dev jest ts-jest @types/jest
এখন, Jest কনফিগারেশন ফাইল তৈরি করুন (jest.config.js):
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
ধরা যাক, একটি UserService আছে, যেটি ব্যবহারকারী সংক্রান্ত কার্যক্রম পরিচালনা করে।
// userService.ts
import { getRepository } from "typeorm";
import { User } from "./entity/User";
export class UserService {
async createUser(name: string, email: string) {
const userRepository = getRepository(User);
const user = new User();
user.name = name;
user.email = email;
await userRepository.save(user);
return user;
}
}
এখন, এই ফাংশনটির জন্য Unit Test তৈরি করা হবে:
// userService.test.ts
import { UserService } from "./userService";
import { getRepository } from "typeorm";
import { User } from "./entity/User";
jest.mock("typeorm", () => ({
getRepository: jest.fn(),
}));
describe("UserService", () => {
it("should create a user", async () => {
const mockSave = jest.fn();
(getRepository as jest.Mock).mockReturnValue({ save: mockSave });
const userService = new UserService();
const user = await userService.createUser("John", "john@example.com");
expect(user.name).toBe("John");
expect(user.email).toBe("john@example.com");
expect(mockSave).toHaveBeenCalled();
});
});
এখানে, jest.mock() ব্যবহার করে getRepository মক করা হয়েছে, যাতে আসল ডাটাবেস ইন্টারঅ্যাকশন না ঘটে। তারপর টেস্টে আমরা দেখাচ্ছি যে, UserService সঠিকভাবে ইউজার তৈরি করছে এবং ডাটাবেসে সেভ করছে।
২. Debugging TypeORM অ্যাপ্লিকেশন
ডিবাগিং হল অ্যাপ্লিকেশনের কোডের সমস্যা বা ত্রুটি চিহ্নিত করা এবং তা সমাধান করার প্রক্রিয়া। TypeORM ডিবাগিং করার জন্য কিছু সাধারণ কৌশল রয়েছে:
১. SQL Logging
TypeORM-এ SQL লগিং সক্রিয় করার মাধ্যমে আপনি দেখতে পারেন কোন SQL কুয়েরি ডাটাবেসে পাঠানো হচ্ছে। এটি ডিবাগিংয়ের জন্য খুবই উপকারী।
import { createConnection } from "typeorm";
createConnection({
type: "mysql",
host: "localhost",
username: "root",
password: "password",
database: "test",
entities: [User],
synchronize: true,
logging: true, // Enable SQL logging
}).then(connection => {
// Connection established
}).catch(error => console.log(error));
এখানে, logging: true সেট করে SQL কুয়েরি লগিং চালু করা হয়েছে, যাতে SQL কুয়েরি টার্মিনালে প্রদর্শিত হয়।
২. TypeORM Debugging Mode
TypeORM-এ ডিবাগিং মোড ব্যবহারের জন্য debug লেভেল লগিং সেট করা যায়।
import { createConnection } from "typeorm";
import "reflect-metadata";
createConnection({
type: "mysql",
host: "localhost",
username: "root",
password: "password",
database: "test",
entities: [User],
synchronize: true,
logging: "all", // Enable all logging for detailed insights
logger: "advanced-console", // Output detailed logs to the console
}).then(connection => {
console.log("Database connected");
}).catch(error => console.log("Error:", error));
এখানে logging: "all" সেট করা হয়েছে, যা ডিবাগিংয়ের সময় সমস্ত কার্যক্রম লগ করে, যেমন SQL কুয়েরি, ডেটাবেস কনফিগারেশন, এবং অন্যান্য ডিবাগ তথ্য।
৩. ডিবাগিং টুলস ব্যবহার করা
TypeORM ডিবাগিংয়ের জন্য আপনি বিভিন্ন টুলস ব্যবহার করতে পারেন:
- Node.js Inspector: এটি Node.js অ্যাপ্লিকেশন ডিবাগ করার জন্য একটি বিল্ট-ইন টুল। আপনি Chrome DevTools বা অন্য ডিবাগিং টুল ব্যবহার করে Node.js অ্যাপ্লিকেশন ডিবাগ করতে পারেন।
- VSCode Debugger: Visual Studio Code ব্যবহার করলে, আপনি সহজেই TypeScript কোড ডিবাগ করতে পারেন এবং ব্রেকপয়েন্ট সেট করে কোডের ভিতরে প্রবাহ চেক করতে পারেন।
৪. TypeORM Validation
TypeORM ডিবাগিংয়ের জন্য ডেটাবেস ভ্যালিডেশন এবং ডেটার সঠিকতা যাচাই করা গুরুত্বপূর্ণ। class-validator প্যাকেজ ব্যবহার করে ভ্যালিডেশন সেট করা যায়, যা TypeORM অ্যাপ্লিকেশনের ডেটা ইনপুট পরীক্ষা করতে সাহায্য করে।
npm install class-validator class-transformer
এরপর, আপনার Entity ক্লাসে ভ্যালিডেশন রুলস প্রয়োগ করতে পারেন:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
import { IsEmail, Length } from "class-validator";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
@Length(3, 50)
name: string;
@Column()
@IsEmail()
email: string;
}
এখানে, class-validator ব্যবহার করে name এবং email ফিল্ডে ভ্যালিডেশন রুলস প্রয়োগ করা হয়েছে। আপনি যখন Entity সেভ করবেন, TypeORM সেই ভ্যালিডেশন চেক করবে।
সারাংশ
Testing এবং Debugging TypeORM অ্যাপ্লিকেশন ডেভেলপমেন্টের অপরিহার্য অংশ। Unit Testing এবং Integration Testing TypeORM অ্যাপ্লিকেশন টেস্ট করার প্রধান পদ্ধতি। টেস্টিংয়ের জন্য Jest বা Mocha ব্যবহার করা যেতে পারে। Debugging করার জন্য TypeORM এ SQL লগিং, ডিবাগিং মোড এবং ডিবাগ টুলস ব্যবহার করা যায়। এছাড়া, ডেটার সঠিকতা নিশ্চিত করতে class-validator ব্যবহার করে ভ্যালিডেশন প্রক্রিয়া সম্পাদন করা যেতে পারে। TypeORM এর সাথে কার্যকরী টেস্টিং এবং ডিবাগging পদ্ধতি অনুসরণ করে আপনি দ্রুত এবং কার্যকরী অ্যাপ্লিকেশন তৈরি করতে পারেন।
Unit Testing এবং Integration Testing: একটি পরিচিতি
Unit Testing এবং Integration Testing দুটি অত্যন্ত গুরুত্বপূর্ণ টেস্টিং কৌশল যা সফটওয়্যার ডেভেলপমেন্টে কোডের গুণগত মান নিশ্চিত করতে ব্যবহৃত হয়।
- Unit Testing: এটি কোডের একক অংশ (ফাংশন বা মেথড) টেস্ট করে। এর উদ্দেশ্য হচ্ছে নিশ্চিত করা যে, প্রতিটি ফাংশন তার নির্ধারিত কাজ সঠিকভাবে করছে।
- Integration Testing: এটি একাধিক অংশের বা মডিউলের একত্রে কাজ পরীক্ষা করে। এর উদ্দেশ্য হচ্ছে, একাধিক সিস্টেম বা মডিউল একসাথে সঠিকভাবে কাজ করছে কি না তা যাচাই করা।
TypeORM এ Unit Testing এবং Integration Testing সেটআপ করা বেশ গুরুত্বপূর্ণ, কারণ এতে ডেটাবেস ইন্টারঅ্যাকশন, রেপোজিটরি অপারেশন, এবং সিস্টেমের বিভিন্ন অংশ পরীক্ষা করা সহজ হয়।
Unit Testing এবং Integration Testing এর জন্য Setup
TypeORM এর জন্য Unit Testing এবং Integration Testing সেটআপ করতে, আমরা Jest বা Mocha-এর মতো টেস্টিং ফ্রেমওয়ার্ক এবং ts-jest বা ts-node-এর মতো TypeScript সমর্থক টুলস ব্যবহার করব। নিচে একটি সাধারণ Jest এবং TypeORM এর জন্য টেস্ট সেটআপের উদাহরণ দেওয়া হয়েছে।
১. Jest ইনস্টলেশন এবং সেটআপ
Jest হলো একটি জনপ্রিয় টেস্টিং ফ্রেমওয়ার্ক যা দ্রুত এবং সহজে Unit Testing এবং Integration Testing পরিচালনা করতে সাহায্য করে। TypeORM-এর সাথে Jest ব্যবহার করার জন্য প্রথমে প্রয়োজনীয় প্যাকেজগুলো ইনস্টল করতে হবে।
Jest ইনস্টল করা:
npm install --save-dev jest ts-jest @types/jest
- jest: Jest টেস্টিং ফ্রেমওয়ার্ক।
- ts-jest: TypeScript ফাইলগুলি Jest দ্বারা রান করার জন্য একটি টুল।
- @types/jest: Jest এর জন্য TypeScript টাইপ ডিফিনিশন।
Jest কনফিগারেশন:
Jest সেটআপ করার জন্য একটি jest.config.js ফাইল তৈরি করুন।
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
transform: {
'^.+\\.ts$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
};
এই কনফিগারেশনটি TypeScript ফাইল রান করার জন্য ts-jest ব্যবহার করবে এবং node.js পরিবেশে টেস্ট চলবে।
২. TypeORM Setup for Testing
টেস্টিং এর জন্য, আপনি in-memory database বা mock database ব্যবহার করতে পারেন, যেমন SQLite। এতে মূল ডেটাবেসের পরিবর্তে একটি দ্রুত ও সহজ ডেটাবেস তৈরি হবে যা টেস্ট চলাকালীন ব্যবহার করা হবে।
Testing Database Setup (SQLite):
import { createConnection } from "typeorm";
createConnection({
type: "sqlite",
database: ":memory:",
entities: [User],
synchronize: true, // synchronize: true ensures that the schema is created automatically
}).then(() => {
console.log('In-memory database connected for testing.');
});
এখানে, SQLite ব্যবহার করা হয়েছে যা ইন-মেমরি ডেটাবেস হিসাবে কাজ করবে এবং টেস্টিংয়ের জন্য সহজে ডেটাবেস তৈরি করবে।
৩. Unit Test উদাহরণ
Unit Testing-এ আমরা একক ফাংশনের কার্যকারিতা পরীক্ষা করি। নিচে একটি TypeORM রেপোজিটরি ফাংশনের জন্য Unit Test করার উদাহরণ দেওয়া হলো।
User Entity:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
email: string;
}
Test: UserRepository:
import { createConnection, getRepository } from "typeorm";
import { User } from "./User";
import { Connection } from "typeorm";
import { Repository } from "typeorm";
describe('User Repository Tests', () => {
let connection: Connection;
let userRepository: Repository<User>;
beforeAll(async () => {
connection = await createConnection({
type: "sqlite",
database: ":memory:",
entities: [User],
synchronize: true,
});
userRepository = connection.getRepository(User);
});
afterAll(async () => {
await connection.close();
});
it('should save a user', async () => {
const user = new User();
user.name = 'John Doe';
user.email = 'john@example.com';
const savedUser = await userRepository.save(user);
expect(savedUser.name).toBe('John Doe');
expect(savedUser.email).toBe('john@example.com');
});
it('should find a user by id', async () => {
const user = new User();
user.name = 'Jane Doe';
user.email = 'jane@example.com';
const savedUser = await userRepository.save(user);
const foundUser = await userRepository.findOne(savedUser.id);
expect(foundUser).not.toBeNull();
expect(foundUser!.name).toBe('Jane Doe');
});
});
এখানে, beforeAll-এ আমরা ইন-মেমরি SQLite ডেটাবেসের সাথে সংযোগ করছি এবং User টেবিল তৈরি করছি। পরে it ব্লকগুলিতে বিভিন্ন CRUD অপারেশন যাচাই করা হচ্ছে।
৪. Integration Test উদাহরণ
Integration Testing-এ আমরা একাধিক মডিউল বা সিস্টেমের সংযোগ পরীক্ষা করি। TypeORM-এ Integration Testing এর জন্য আমরা সাধারণত বিভিন্ন মডেল বা সার্ভিসের সমন্বয়ে একটি পুরো সিস্টেম টেস্ট করি।
Test: Create and Find User with Post Entity:
ধরা যাক, আমাদের একটি User এবং একটি Post মডেল রয়েছে এবং আমরা যাচাই করতে চাই যে, একটি ব্যবহারকারী এবং তার পোস্ট সঠিকভাবে কাজ করছে।
import { createConnection, getRepository } from "typeorm";
import { User } from "./User";
import { Post } from "./Post";
import { Connection } from "typeorm";
import { Repository } from "typeorm";
describe('User and Post Integration Test', () => {
let connection: Connection;
let userRepository: Repository<User>;
let postRepository: Repository<Post>;
beforeAll(async () => {
connection = await createConnection({
type: "sqlite",
database: ":memory:",
entities: [User, Post],
synchronize: true,
});
userRepository = connection.getRepository(User);
postRepository = connection.getRepository(Post);
});
afterAll(async () => {
await connection.close();
});
it('should create a user and associated posts', async () => {
const user = new User();
user.name = 'John Doe';
user.email = 'john@example.com';
const savedUser = await userRepository.save(user);
const post1 = new Post();
post1.title = "Post 1";
post1.content = "Content of Post 1";
post1.user = savedUser;
const post2 = new Post();
post2.title = "Post 2";
post2.content = "Content of Post 2";
post2.user = savedUser;
await postRepository.save([post1, post2]);
const userWithPosts = await userRepository.findOne(savedUser.id, { relations: ["posts"] });
expect(userWithPosts!.posts.length).toBe(2);
expect(userWithPosts!.posts[0].title).toBe("Post 1");
expect(userWithPosts!.posts[1].title).toBe("Post 2");
});
});
এখানে, User এবং Post এর মধ্যে একটি One-to-Many সম্পর্ক তৈরি করা হয়েছে এবং টেস্টে যাচাই করা হচ্ছে যে, একটি ব্যবহারকারী এবং তার সম্পর্কিত পোস্ট গুলো সঠিকভাবে ডেটাবেসে সেভ এবং লোড হচ্ছে।
সারাংশ
Unit Testing এবং Integration Testing TypeORM এর জন্য একটি গুরুত্বপূর্ণ অংশ। Jest টেস্টিং ফ্রেমওয়ার্ক ব্যবহার করে TypeORM মডেল এবং রেপোজিটরি টেস্ট করা সম্ভব। Unit Testing-এ একক ফাংশন বা মডিউল পরীক্ষা করা হয় এবং Integration Testing-এ একাধিক মডিউল একত্রে কাজ করছে কিনা তা পরীক্ষা করা হয়। TypeORM-এ ডেটাবেস অপারেশন, রিলেশন এবং CRUD ফাংশনালিটি টেস্ট করার জন্য ইন-মেমরি SQLite বা অন্যান্য ডাটাবেস ব্যবহার করা যেতে পারে।
Mocking এবং Dependency Injection (DI): একটি পরিচিতি
Mocking এবং Dependency Injection (DI) হল টেস্টিং এবং সফটওয়্যার ডেভেলপমেন্টের গুরুত্বপূর্ণ ধারণা যা কোডের টেস্টিং এবং রিইউজেবিলিটি উন্নত করতে সহায়তা করে।
- Mocking হল একটি টেস্টিং কৌশল যেখানে ডিপেনডেন্সি বা এক্সটার্নাল সিস্টেমগুলোকে ভুয়া বা "mock" অবজেক্ট দিয়ে প্রতিস্থাপন করা হয়, যাতে টেস্ট চলাকালে প্রকৃত সিস্টেম বা ডেটার উপর নির্ভর না করে টেস্ট করা যায়।
- Dependency Injection (DI) হল একটি ডিজাইন প্যাটার্ন যা কোডের বিভিন্ন অংশের মধ্যে ডিপেনডেন্সি (যেমন সার্ভিস, ডেটাবেস কনেকশন) ইনজেক্ট করে। এটি কোডের মডুলারিটি এবং টেস্টেবিলিটি উন্নত করে।
TypeORM-এ Mocking এবং Dependency Injection ব্যবহার করে ডেটাবেস অপারেশন বা সার্ভিস লজিকের জন্য ইউনিট টেস্ট এবং ইন্টিগ্রেশন টেস্ট তৈরি করা হয়।
TypeORM এর জন্য Mocking এবং Dependency Injection
১. Mocking TypeORM
TypeORM এর সাথে টেস্টিং করার সময় ডেটাবেসের সাথে ইন্টারঅ্যাক্ট না করে কেবলমাত্র লজিকের টেস্টিং করার জন্য Mocking ব্যবহৃত হয়। এর মাধ্যমে TypeORM এর Repository, EntityManager, অথবা QueryBuilder ইত্যাদি মক করা যেতে পারে।
Mocking TypeORM Repository:
প্রথমে jest বা অন্য কোনো টেস্টিং ফ্রেমওয়ার্ক ব্যবহার করে TypeORM এর Repository মক করা হবে। jest একটি জনপ্রিয় টেস্টিং লাইব্রেরি যা mocking সহজে পরিচালনা করতে সাহায্য করে।
Example: Mocking TypeORM Repository using Jest
import { getRepository } from "typeorm";
import { User } from "./entity/User";
// Mocking the repository
jest.mock("typeorm", () => ({
getRepository: jest.fn(),
}));
describe('UserService', () => {
it('should return all users', async () => {
const mockUserRepository = {
find: jest.fn().mockResolvedValue([{ id: 1, name: 'John' }]),
};
// Mocking getRepository to return the mocked repository
(getRepository as jest.Mock).mockReturnValue(mockUserRepository);
const userService = new UserService();
const users = await userService.getAllUsers();
expect(users).toEqual([{ id: 1, name: 'John' }]);
expect(mockUserRepository.find).toHaveBeenCalledTimes(1);
});
});
এখানে, getRepository মক করা হয়েছে, এবং UserRepository এর find মেথডও মক করা হয়েছে। এর মাধ্যমে Unit Testing করা হয়েছে, যেখানে প্রকৃত ডেটাবেস ব্যবহার করা হয়নি।
২. Dependency Injection (DI) ব্যবহার করা
Dependency Injection (DI) ব্যবহৃত হয় ডিপেনডেন্সি (যেমন সার্ভিস, রেপোজিটরি) অন্য অবজেক্টের মধ্যে ইনজেক্ট করার জন্য। TypeORM-এ DI ব্যবহার করলে আপনি কমপ্লেক্স ডেটাবেস লজিক বা সার্ভিসগুলিকে আরও সহজভাবে টেস্ট করতে পারবেন।
TypeORM এর সাথে DI ব্যবহার করতে সাধারণত একটি DI container (যেমন InversifyJS বা Typedi) ব্যবহার করা হয়, যেটি ডিপেনডেন্সি ম্যানেজ করে এবং অবজেক্ট ইনজেকশন পরিচালনা করে।
Dependency Injection with TypeORM:
InversifyJS ব্যবহার করে TypeORM এর সাথে DI কিভাবে সেটআপ করবেন তা এখানে দেখানো হলো।
- Install dependencies:
npm install inversify reflect-metadata typeorm
- Create DI container and setup dependencies:
import { Container, injectable } from "inversify";
import { UserRepository } from "./repositories/UserRepository";
// Create the container
const container = new Container();
// Define a service that requires a dependency (e.g., UserRepository)
@injectable()
class UserService {
private userRepository: UserRepository;
constructor(userRepository: UserRepository) {
this.userRepository = userRepository;
}
async getAllUsers() {
return this.userRepository.find();
}
}
// Register dependencies in container
container.bind(UserService).toSelf();
container.bind(UserRepository).toSelf();
// Get the instance of the UserService
const userService = container.get(UserService);
// Use the service
userService.getAllUsers().then((users) => {
console.log(users);
});
এখানে, UserService এর মধ্যে UserRepository ইনজেক্ট করা হয়েছে। InversifyJS এর মাধ্যমে TypeORM রেপোজিটরি এবং সার্ভিসগুলোকে সেন্ট্রালাইজডভাবে পরিচালনা করা হচ্ছে, যা টেস্টিং এবং স্কেলেবিলিটি সহজ করে তোলে।
৩. Mocking TypeORM EntityManager
TypeORM এ EntityManager দিয়ে ডেটাবেস পরিচালনা করা যায়। এটি সার্ভিসে ইঞ্জেক্ট করা যেতে পারে এবং যদি আপনি EntityManager এর সাথে কাজ করেন তবে এটি মক করা যেতে পারে।
Example: Mocking EntityManager in TypeORM:
import { EntityManager } from "typeorm";
import { User } from "./entity/User";
import { getManager } from "typeorm";
// Mocking the EntityManager
jest.mock("typeorm", () => ({
getManager: jest.fn(),
}));
describe("UserService", () => {
it("should create a user", async () => {
const mockEntityManager = {
save: jest.fn().mockResolvedValue({ id: 1, name: "John" }),
};
(getManager as jest.Mock).mockReturnValue(mockEntityManager);
const userService = new UserService();
const user = await userService.createUser({ name: "John" });
expect(user).toEqual({ id: 1, name: "John" });
expect(mockEntityManager.save).toHaveBeenCalledTimes(1);
});
});
এখানে EntityManager এর save মেথড মক করা হয়েছে, যাতে আপনি ডেটাবেসে কোন ডেটা সেভ না করেও টেস্টিং করতে পারেন।
সারাংশ
Mocking এবং Dependency Injection (DI) হল TypeORM এর সাথে টেস্টিং করার জন্য অত্যন্ত গুরুত্বপূর্ণ কৌশল। Mocking ব্যবহার করে আপনি ডেটাবেস ইন্টারঅ্যাকশন ছাড়া আপনার লজিক টেস্ট করতে পারেন, এবং DI ব্যবহার করে আপনি টেস্টিং এবং স্কেলেবিলিটির জন্য ডিপেনডেন্সি ইনজেকশন সহজে পরিচালনা করতে পারেন। Jest, InversifyJS, Typedi ইত্যাদি টুলসের মাধ্যমে এই কৌশলগুলি কার্যকরভাবে ব্যবহৃত হয় TypeORM প্রোজেক্টে।
TypeORM এর সাথে Unit Testing এবং Integration Testing
TypeORM একটি শক্তিশালী ORM (Object-Relational Mapping) লাইব্রেরি যা ডেটাবেস ম্যানেজমেন্টের জন্য ব্যবহৃত হয়। যখন আমরা TypeORM ভিত্তিক অ্যাপ্লিকেশন তৈরি করি, তখন আমাদের অ্যাপ্লিকেশনের বিভিন্ন অংশের জন্য Unit Testing এবং Integration Testing করতে হয়। Jest এবং Mocha হল সবচেয়ে জনপ্রিয় testing frameworks যা TypeORM এর সাথে ব্যবহৃত হতে পারে।
Testing frameworks ব্যবহার করে, আপনি আপনার কোডের বৈধতা নিশ্চিত করতে পারেন এবং কোনো পরিবর্তন করার সময় আগের কাজগুলো ঠিক আছে কিনা তা যাচাই করতে পারবেন। Jest এবং Mocha উভয়ই JavaScript Testing Framework যা TypeORM সহ ব্যবহার করা যায়।
১. Jest Setup এবং TypeORM Testing
Jest একটি ফাস্ট এবং সহজ testing framework, যা কোডিংয়ের সময় পারফরম্যান্স এবং উন্নত পরীক্ষার সুবিধা প্রদান করে। TypeORM সহ Jest ব্যবহার করার জন্য, আপনাকে কিছু নির্দিষ্ট কনফিগারেশন এবং সেটআপ করতে হবে।
১.১ Jest ইনস্টলেশন এবং সেটআপ
- Jest এবং TypeORM-এর জন্য প্রয়োজনীয় প্যাকেজ ইনস্টল করুন:
npm install --save-dev jest ts-jest @types/jest
npm install typeorm reflect-metadata mysql2
- Jest কনফিগারেশন ফাইল তৈরি করুন:
jest.config.js নামক একটি ফাইল তৈরি করুন এবং নিচের কনফিগারেশন সেট করুন:
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
globalSetup: './global-setup.js', // Global setup if needed
setupFilesAfterEnv: ['./jest.setup.ts'], // Custom setup if needed
};
- TypeORM টেস্ট সেটআপ (in-memory ডেটাবেস ব্যবহার):
TypeORM এ Unit Testing করতে হলে একটি ইন-মেমরি ডেটাবেস (যেমন SQLite) ব্যবহার করা সুবিধাজনক। আপনি SQLite ব্যবহার করতে পারেন যেটি টেস্ট চলাকালীন খুব দ্রুত চালু এবং বন্ধ করা যায়।
jest.setup.ts ফাইল তৈরি করুন এবং TypeORM কনফিগারেশন সেট করুন:
import "reflect-metadata";
import { createConnection } from "typeorm";
// Use an in-memory SQLite database for testing
createConnection({
type: "sqlite",
database: ":memory:",
synchronize: true,
entities: [/* Your entities here */],
dropSchema: true, // To drop schema before each test
}).then(() => {
console.log('Test database connected');
}).catch(error => console.log("Error: ", error));
- Unit Test উদাহরণ:
এখন আপনি সহজে TypeORM এর Entity নিয়ে Unit Testing শুরু করতে পারেন। ধরুন, আপনার একটি User Entity রয়েছে, যা name এবং email ফিল্ড নিয়ে কাজ করে।
import { User } from './User'; // Import your User entity
import { getRepository } from 'typeorm';
describe('User entity', () => {
it('should save a user', async () => {
const userRepository = getRepository(User);
const user = new User();
user.name = 'John Doe';
user.email = 'john.doe@example.com';
await userRepository.save(user);
const savedUser = await userRepository.findOne({ where: { name: 'John Doe' } });
expect(savedUser).toBeDefined();
expect(savedUser.name).toBe('John Doe');
});
});
এখানে, TypeORM এর getRepository() ব্যবহার করে একটি নতুন User তৈরি করা হয়েছে এবং সেটি ডেটাবেসে সেভ করা হয়েছে। তারপর, findOne() ব্যবহার করে সেভ করা ইউজারটি খুঁজে বের করা হয়েছে এবং তার নাম যাচাই করা হয়েছে।
২. Mocha Setup এবং TypeORM Testing
Mocha আরেকটি জনপ্রিয় Testing Framework যা TypeORM সহ ব্যবহৃত হতে পারে। Mocha সাধারণত async/await এবং done পদ্ধতি ব্যবহার করে টেস্ট করে থাকে।
২.১ Mocha ইনস্টলেশন এবং সেটআপ
- Mocha এবং প্রয়োজনীয় প্যাকেজ ইনস্টল করুন:
npm install --save-dev mocha chai ts-node @types/mocha @types/chai
npm install typeorm reflect-metadata mysql2
- Mocha টেস্ট কনফিগারেশন:
Mocha টেস্ট চালানোর জন্য একটি test স্ক্রিপ্ট তৈরি করুন:
{
"scripts": {
"test": "mocha -r ts-node/register tests/**/*.test.ts"
}
}
এখানে, ts-node/register ব্যবহার করা হয়েছে যাতে TypeScript ফাইলগুলো সরাসরি Mocha দিয়ে চালানো যায়।
- TypeORM টেস্ট সেটআপ:
Mocha-এর মতো, TypeORM এর জন্যও ইন-মেমরি SQLite ডেটাবেস ব্যবহার করা যেতে পারে।
import "reflect-metadata";
import { createConnection } from "typeorm";
createConnection({
type: "sqlite",
database: ":memory:",
synchronize: true,
entities: [/* Your entities here */],
dropSchema: true,
}).then(() => {
console.log('Connected to in-memory database');
}).catch(error => console.log('Error: ', error));
- Mocha টেস্ট উদাহরণ:
import { expect } from 'chai';
import { User } from './User'; // Import your User entity
import { getRepository } from 'typeorm';
describe('User entity', () => {
it('should create and retrieve a user', async () => {
const userRepository = getRepository(User);
const user = new User();
user.name = 'Jane Doe';
user.email = 'jane.doe@example.com';
await userRepository.save(user);
const savedUser = await userRepository.findOne({ where: { name: 'Jane Doe' } });
expect(savedUser).to.not.be.null;
expect(savedUser.name).to.equal('Jane Doe');
});
});
এখানে, Mocha ব্যবহার করে User Entity এর CRUD অপারেশন টেস্ট করা হয়েছে। chai এর expect ফাংশন ব্যবহার করে টেস্ট আউটপুট যাচাই করা হয়েছে।
৩. Mocking এবং Dependency Injection
কিছু ক্ষেত্রে, TypeORM ব্যবহার করার সময় টেস্টের জন্য ডেটাবেস সংযোগ এবং অ্যাক্সেস মক করতে হতে পারে। এই জন্য Mocking এবং Dependency Injection টেকনিক ব্যবহার করা হয়।
Mocking Example:
sinon বা jest.mock() এর মাধ্যমে TypeORM এর Repository মক করা যেতে পারে।
import sinon from 'sinon';
import { getRepository } from 'typeorm';
import { User } from './User';
describe('User repository', () => {
it('should mock the repository', async () => {
const userRepositoryMock = sinon.stub(getRepository(User), 'findOne').resolves({ name: 'Mocked User' });
const user = await getRepository(User).findOne();
expect(user.name).toBe('Mocked User');
userRepositoryMock.restore(); // Restore the original method
});
});
এখানে, sinon.stub() ব্যবহার করে getRepository(User) এর findOne মেথড মক করা হয়েছে।
সারাংশ
Jest এবং Mocha হল দুটি জনপ্রিয় Testing Framework যা TypeORM এর সাথে ব্যবহৃত হতে পারে। Jest সাধারণত দ্রুত এবং সহজ টেস্টিংয়ের জন্য ব্যবহৃত হয়, যখন Mocha টেস্টিংয়ের জন্য আরও ফ্লেক্সিবিলিটি প্রদান করে। TypeORM এর সাথে Unit Testing এবং Integration Testing কার্যকরীভাবে পরিচালনা করতে, আপনি ইন-মেমরি ডেটাবেস, Repository Pattern, এবং কাস্টম কুয়েরি ব্যবহার করতে পারেন। Mocking এবং Dependency Injection এর মাধ্যমে আপনি ডেটাবেস অপারেশনগুলোকে মক করে টেস্টিং আরও সহজ করতে পারবেন।
TypeORM এর Debugging Techniques
TypeORM ব্যবহার করার সময় বিভিন্ন ধরনের সমস্যা বা বাগ দেখা দিতে পারে, যেমন ডাটাবেস সংযোগ সমস্যা, ক্যোয়েরি অপটিমাইজেশন সমস্যা, রিলেশনাল টেবিল ম্যানেজমেন্ট ইত্যাদি। TypeORM-এর সাথে কাজ করার সময়ে সমস্যা সমাধান করতে কিছু ডিবাগিং টেকনিক জানা প্রয়োজন।
এখানে TypeORM এর সাধারণ ডিবাগিং টেকনিক এবং Common Issues এর সমাধান নিয়ে আলোচনা করা হবে।
১. TypeORM এর সাথে ডিবাগিং সক্ষম করা
TypeORM-এ ডিবাগিং সক্ষম করতে logging বৈশিষ্ট্যটি ব্যবহার করা হয়, যা TypeORM কোডের ভিতরে চলমান ক্যোয়েরি এবং তাদের ফলাফল দেখতে সাহায্য করে। আপনি ormconfig.json ফাইলে অথবা কোডে সরাসরি logging অপশন সেট করতে পারেন।
Example: Logging Enable করার জন্য
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "your-password",
"database": "test",
"logging": true, // Enable logging
"entities": [
"src/entity/**/*.ts"
],
"synchronize": true
}
এখানে, logging: true সেট করলে, TypeORM সমস্ত SQL ক্যোয়েরি কনসোলে লগ করবে, যা ডিবাগিংয়ের জন্য খুবই উপকারী।
২. Query Builder ব্যবহার করে ক্যোয়েরি ডিবাগিং
TypeORM-এর QueryBuilder ব্যবহার করে আপনি খুব সহজে কাস্টম ক্যোয়েরি তৈরি এবং পরীক্ষা করতে পারেন। এটি ডিবাগিংয়ের সময় কোডের গতি এবং কার্যকারিতা পর্যবেক্ষণ করতে সহায়ক।
Example: QueryBuilder Logs
import { getRepository } from "typeorm";
import { User } from "./entity/User";
const userRepository = getRepository(User);
// Create a query builder instance
const query = userRepository.createQueryBuilder("user");
// Log the SQL query to the console
console.log(query.getQuery()); // Get the raw SQL query
// Execute the query
const users = await query.getMany();
console.log(users);
এখানে getQuery() ব্যবহার করে SQL ক্যোয়েরি দেখা যাবে, যাতে ডিবাগিংয়ের জন্য যেকোনো অস্বাভাবিক আচরণ পরীক্ষা করা যায়।
৩. Entity Synchronization Issues
একটি সাধারণ সমস্যা হল synchronize অপশন সঠিকভাবে কাজ না করা, বিশেষ করে যখন ডেটাবেস স্কিমা পরিবর্তন হয় এবং TypeORM এর সাথে ডেটাবেস আপডেট করা দরকার হয়। TypeORM যখন synchronize: true থাকে, তখন এটি স্বয়ংক্রিয়ভাবে ডেটাবেসের স্কিমা আপডেট করে, তবে কখনও কখনও এটি সঠিকভাবে কাজ নাও করতে পারে।
সমাধান:
- Manually Migration: যদি
synchronize: trueকাজ না করে, তবে migrations ব্যবহার করুন।
typeorm migration:generate -n MyMigration
typeorm migration:run
- Clear Cache: কখনও কখনও metadata সঠিকভাবে লোড না হলে সমস্যা হতে পারে, তাই cache পরিষ্কার করা হতে পারে।
npm run typeorm:cache-clear
৪. Circular Dependency Issues
TypeORM ব্যবহার করার সময় কখনও কখনও circular dependency সমস্যা দেখা দেয়, বিশেষ করে যখন একটি Entity একাধিক সম্পর্কের মধ্যে থাকে। যেমন ManyToOne, OneToMany, ManyToMany এর মধ্যে Circular Dependency হতে পারে।
সমাধান:
Circular dependency সমস্যার সমাধানে Lazy Loading ব্যবহার করতে পারেন, অথবা Forward Reference দিয়ে Entity গুলোকে রেফারেন্স করতে পারেন।
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";
import { User } from "./User";
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@ManyToOne(() => User)
user: User;
}
এখানে () => User ব্যবহার করার মাধ্যমে টাইপ রেফারেন্স করতে Lazy Loading সক্ষম করা হচ্ছে, যাতে circular dependency থেকে রক্ষা পাওয়া যায়।
৫. Database Connection Issues
TypeORM ব্যবহার করার সময় সাধারণত database connection সংক্রান্ত সমস্যা হয়, যেমন ডাটাবেস সার্ভার না পাওয়া, ভুল পাসওয়ার্ড, ভুল ডাটাবেস নাম ইত্যাদি।
সমাধান:
- Configuration Check: প্রথমেই আপনার
ormconfig.jsonবা ডাটাবেস কনফিগারেশন সঠিকভাবে চেক করুন। - Database Driver: আপনি যদি PostgreSQL ব্যবহার করেন, তবে
pgড্রাইভার ইনস্টল করা আছে কিনা তা চেক করুন:
npm install pg
- Connection Retry: কখনও কখনও ডাটাবেস সার্ভারের সাথে সংযোগে সমস্যা হতে পারে, তাই ডাটাবেস কনফিগারেশনে retry মেকানিজম ব্যবহার করা যেতে পারে।
৬. Data Validation Errors
TypeORM এ validation errors সাধারণত class-validator বা class-transformer এর মাধ্যমে পরিচালিত হয়। এই ধরনের ত্রুটির ক্ষেত্রে সঠিক DTO (Data Transfer Object) তৈরি করা এবং তা কনফিগার করা গুরুত্বপূর্ণ।
উদাহরণ:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
import { IsString, IsInt, Min } from "class-validator";
@Entity()
export class Product {
@PrimaryGeneratedColumn()
id: number;
@Column()
@IsString()
name: string;
@Column()
@IsInt()
@Min(0)
price: number;
}
এখানে, class-validator ব্যবহার করে ডেটা ভ্যালিডেশন করা হয়েছে। TypeORM ত্রুটি দেখালে আপনি ভ্যালিডেশন ত্রুটির বিস্তারিত দেখতে পাবেন।
৭. Query Performance Issues
TypeORM এর ক্যোয়েরি পারফরম্যান্সের সমস্যাও হতে পারে, বিশেষ করে যখন বড় ডেটাবেস বা জটিল ক্যোয়েরি তৈরি করা হয়। আপনি logging: true এর মাধ্যমে ক্যোয়েরি লগ করতে পারেন এবং পারফরম্যান্স অপটিমাইজেশন করতে পারেন।
সমাধান:
- Indexing: ডেটাবেসের টেবিলগুলোতে সঠিকভাবে index ব্যবহার করুন।
- Query Optimization: TypeORM-এর QueryBuilder ব্যবহার করে কাস্টম এবং অপটিমাইজড ক্যোয়েরি তৈরি করুন।
- Batching: বড় ডেটার ক্ষেত্রে batching ব্যবহার করে একাধিক ইনসার্ট বা আপডেট কার্যকরীভাবে সম্পাদন করুন।
সারাংশ
TypeORM ব্যবহার করার সময় বিভিন্ন ধরনের সমস্যা দেখা দিতে পারে, যেমন database connection, performance, validation, circular dependency ইত্যাদি। তবে, সঠিকভাবে ডিবাগিং টেকনিক এবং সমস্যা সমাধান কৌশলগুলি জানা থাকলে, TypeORM এর সাথে কাজ করা অনেক সহজ এবং দক্ষ হয়ে ওঠে। এর মাধ্যমে আপনি অ্যাপ্লিকেশনের পারফরম্যান্স এবং কোডের নির্ভরযোগ্যতা বৃদ্ধি করতে পারেন।
Read more