Ujian Unit Prosedur tRPC
Pelajari cara menulis ujian unit terpencil untuk prosedur tRPC individu menggunakan rangka kerja ujian popular.
Ujian Unit Prosedur tRPC ialah pelajaran API tRPC Selamat Jenis dari Hujung ke Hujung percuma di CoddyKit. Ini ialah pelajaran 1 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran API tRPC Selamat Jenis dari Hujung ke Hujung, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus API tRPC Selamat Jenis dari Hujung ke Hujung merangkumi sejumlah 4 pelajaran.
Ujian Unit Prosedur tRPC
Selamat datang! Dalam pelajaran ini, kita akan mendalami ujian unit untuk tRPC. Ujian unit memfokuskan pengesahan bahagian kod individu yang terpencil, bagi memastikan bahagian tersebut berfungsi seperti yang dijangka.
Untuk tRPC, "unit" biasanya merujuk kepada satu prosedur (pertanyaan atau mutasi). Kita akan belajar menguji prosedur ini secara berasingan tanpa memerlukan pelayan penuh yang sedang berjalan.
Manfaat Ujian Prosedur
Ujian unit prosedur tRPC menawarkan beberapa kelebihan utama:
- Kebolehpercayaan: Mengesan pepijat lebih awal dalam pembangunan sebelum sampai ke pengeluaran.
- Kelajuan: Ujian berjalan dengan pantas dan memberikan maklum balas serta-merta.
- Pengasingan: Mengenal pasti masalah pada prosedur tertentu, bukan integrasi yang kompleks.
- Keselamatan Jenis: Memastikan input dan output prosedur anda sepadan dengan takrif TypeScript anda.
Alat Penting untuk Ujian tRPC
Walaupun anda boleh menggunakan pelbagai alat, pilihan popular untuk projek TypeScript termasuk Jest atau Vitest sebagai pelaksana ujian. Untuk ujian unit bahagian belakang tRPC, kita terutamanya memfokuskan TypeScript dan keupayaan penegasan pelaksana ujian.
Kita akan mensimulasikan cara memanggil pengendali dalaman prosedur secara terus untuk ujian, iaitu konsep teras tanpa mengira pelaksana ujian yang dipilih.
Menghuraikan Ujian Prosedur
Untuk menguji unit prosedur tRPC, anda perlu:
- Import prosedur.
- Cipta konteks olok-olok (
ctx). - Panggil pengendali dalaman prosedur secara terus, contohnya
_def.queryatau_def.mutation. - Buat penegasan terhadap nilai yang dikembalikan atau sebarang kesan sampingan.
Mari lihat contoh asas:
// test-hello.ts
import { initTRPC } from '@trpc/server';
// 1. Define a simple tRPC procedure (or import from your app)
const t = initTRPC.create();
const helloProcedure = t.procedure
.query(() => 'Hello tRPC');
// 2. Create a mock context (empty for this simple case)
const mockContext = {};
async function runHelloTest() {
console.log("--- Testing 'helloProcedure' ---");
// 3. Call the procedure's internal query handler
const result = await helloProcedure._def.query({
ctx: mockContext,
input: undefined, // No input required
path: 'hello', // The procedure's path
type: 'query' // It's a query procedure
});
// 4. Assert the result
console.log(`Expected: 'Hello tRPC'`);
console.log(`Actual: '${result}'`);
if (result === 'Hello tRPC') {
console.log("Test Passed: The procedure returned the correct message.");
} else {
console.log("Test Failed: Unexpected return value.");
}
}
runHelloTest();Mengasingkan dengan Konteks Olok-olok
Objek ctx dalam prosedur tRPC selalunya mengandungi kebergantungan penting seperti status pengesahan pengguna, sambungan pangkalan data atau perkhidmatan lain. Untuk memastikan ujian unit terasing, anda mesti mengolok-olokkan konteks ini.
Konteks olok-olok menyediakan versi palsu kebergantungan ini, lalu membolehkan prosedur berjalan tanpa berinteraksi dengan sistem luaran sebenar.
// test-mock-context.ts
// Simulate a mock context for a procedure needing a user and database.
interface MockUser {
id: string;
name: string;
}
interface MockDB {
findUserById: (id: string) => Promise<MockUser | null>;
// ... other mock database methods
}
// Our mock database implementation
const mockDB: MockDB = {
findUserById: async (id: string) => {
console.log(`Mock DB: Finding user with ID: ${id}`);
if (id === 'user123') {
return { id: 'user123', name: 'Alice' };
}
return null;
},
};
// Our mock tRPC context factory
const createMockContext = (user?: MockUser) => ({
user: user || null,
db: mockDB,
// Add any other mocked services here
});
async function demonstrateMockContext() {
console.log("--- Demonstrating Mock Context ---");
const ctxWithUser = createMockContext({ id: 'user123', name: 'Alice' });
console.log("Context with user: ", JSON.stringify(ctxWithUser.user));
const ctxWithoutUser = createMockContext();
console.log("Context without user: ", JSON.stringify(ctxWithoutUser.user));
// You can even test mock DB calls
const foundUser = await ctxWithUser.db.findUserById('user123');
console.log("Found user via mock DB: ", JSON.stringify(foundUser));
}
demonstrateMockContext();Contoh: Membuat Pertanyaan Profil Pengguna
Mari gabungkan perkara yang telah dipelajari untuk menguji pertanyaan yang mengambil profil pengguna. Prosedur ini bergantung pada ctx untuk maklumat pengguna dan pangkalan data olok-olok.
Kita akan mencipta konteks olok-olok yang mensimulasikan pengguna yang disahkan dan membuat penegasan bahawa profil yang betul dikembalikan.
// test-user-query.ts
import { initTRPC } from '@trpc/server';
// Define our mock DB and User types
interface MockUser { id: string; name: string; email: string; }
interface MockDB { getUserById: (id: string) => Promise<MockUser | null>; }
// Mock DB implementation
const mockDB: MockDB = {
getUserById: async (id: string) => {
if (id === 'alice123') {
return { id: 'alice123', name: 'Alice', email: 'alice@example.com' };
}
return null;
},
};
// Create a mock context for our tests
const createMockContext = (userId?: string) => ({
user: userId ? { id: userId, name: 'TestUser' } : null, // Simplified user obj
db: mockDB,
});
// Our tRPC setup
const t = initTRPC.create();
// The procedure we want to test
const getUserProfile = t.procedure
.query(async ({ ctx }) => {
if (!ctx.user) {
throw new Error('Unauthorized');
}
const user = await ctx.db.getUserById(ctx.user.id);
if (!user) {
throw new Error('User not found');
}
return { id: user.id, name: user.name, email: user.email };
});
async function runUserProfileTest() {
console.log("--- Testing 'getUserProfile' ---");
// Test Case 1: Authorized user
const authCtx = createMockContext('alice123');
try {
const result = await getUserProfile._def.query({
ctx: authCtx, input: undefined, path: 'getUserProfile', type: 'query'
});
console.log("Authorized User Test Result: ", JSON.stringify(result));
if (result.id === 'alice123' && result.name === 'Alice') {
console.log("Authorized User Test Passed!");
} else {
console.log("Authorized User Test Failed!");
}
} catch (error: any) {
console.log("Authorized User Test Failed with error: ", error.message);
}
// Test Case 2: Unauthorized user
const unauthCtx = createMockContext(undefined);
try {
await getUserProfile._def.query({
ctx: unauthCtx, input: undefined, path: 'getUserProfile', type: 'query'
});
console.log("Unauthorized User Test Failed: Should have thrown an error.");
} catch (error: any) {
console.log("Unauthorized User Test Result (Expected Error): ", error.message);
if (error.message === 'Unauthorized') {
console.log("Unauthorized User Test Passed!");
} else {
console.log("Unauthorized User Test Failed: Unexpected error message.");
}
}
}
runUserProfileTest();Mengesahkan Input dengan Zod
Banyak prosedur menerima input yang selalunya disahkan menggunakan skema Zod. Semasa menguji unit, anda perlu menyediakan input yang sah dan tidak sah bagi memastikan logik prosedur serta pengesahan Zod berfungsi dengan betul.
Parameter input dalam pengendali _def.query atau _def.mutation ialah tempat anda menghantar input ujian ini.
// test-post-by-id.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
// Mock DB for posts
interface MockPost { id: string; title: string; content: string; }
interface MockDB { getPostById: (id: string) => Promise<MockPost | null>; }
const mockDB: MockDB = {
getPostById: async (id: string) => {
if (id === 'post1') {
return { id: 'post1', title: 'First Post', content: 'Lorem ipsum...' };
}
return null;
},
};
const t = initTRPC.create();
const mockContext = { db: mockDB }; // Simple context
// Procedure with Zod input validation
const getPostById = t.procedure
.input(z.object({
id: z.string().min(1, "ID cannot be empty") // Simplified validation for example
}))
.query(async ({ input, ctx }) => {
const post = await ctx.db.getPostById(input.id);
if (!post) {
throw new Error('Post not found');
}
return post;
});
async function runPostByIdTest() {
console.log("--- Testing 'getPostById' ---");
// Test Case 1: Valid input, post found
try {
const result = await getPostById._def.query({
ctx: mockContext,
input: { id: 'post1' }, // Valid input
path: 'getPostById',
type: 'query'
});
console.log("Valid Input (Found) Test Result: ", JSON.stringify(result));
if (result.id === 'post1') {
console.log("Valid Input (Found) Test Passed!");
} else {
console.log("Valid Input (Found) Test Failed!");
}
} catch (error: any) {
console.log("Valid Input (Found) Test Failed with error: ", error.message);
}
// Test Case 2: Valid input, post not found
try {
await getPostById._def.query({
ctx: mockContext,
input: { id: 'post2' }, // Valid format, but not in mock DB
path: 'getPostById',
type: 'query'
});
console.log("Valid Input (Not Found) Test Failed: Should have thrown error.");
} catch (error: any) {
console.log("Valid Input (Not Found) Test Result (Expected Error): ", error.message);
if (error.message === 'Post not found') {
console.log("Valid Input (Not Found) Test Passed!");
} else {
console.log("Valid Input (Not Found) Test Failed: Unexpected error.");
}
}
}
runPostByIdTest();Ujian Unit Perubahan Data
Prosedur mutasi mengubah data. Semasa mengujinya, anda perlu memastikan prosedur tersebut melakukan tindakan yang betul dan mengembalikan hasil yang dijangka. Perkara penting di sini ialah mengolok-olokkan sebarang sistem luaran (seperti pangkalan data) untuk mengesahkan bahawa mutasi berinteraksi dengannya seperti yang dijangka.
Anda selalunya akan menggunakan fungsi olok-olok (contohnya olok-olok Jest) untuk menjejaki panggilan kepada kebergantungan yang diolok-olokkan.
// test-create-user.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
// Mock DB for users
interface UserInput { name: string; email: string; }
interface MockDB { createUser: (data: UserInput) => Promise<{ id: string } & UserInput>; }
// --- Mocking 'jest.fn' for runnable code ---
// In a real environment, Jest would provide this. This is a simplified stand-in.
declare const jest: any; // Declare jest to avoid TS error in this isolated snippet
if (typeof jest === 'undefined') {
globalThis.jest = {
fn: (impl?: Function) => {
const mockFunc: any = (...args: any[]) => {
mockFunc.calls.push(args);
return impl ? impl(...args) : undefined;
};
mockFunc.calls = [];
mockFunc.mockClear = () => { mockFunc.calls = []; };
return mockFunc;
}
};
}
// --- End Mocking 'jest.fn' ---
// Implement a mock database with a 'mock' function for createUser
const mockCreateUser = jest.fn(async (data: UserInput) => {
// Simulate database ID generation
const newId = `user_${Math.random().toString(36).substr(2, 9)}`;
console.log(`Mock DB: Creating user with ID ${newId}`);
return { id: newId, ...data };
});
const mockDB: MockDB = {
createUser: mockCreateUser,
};
const t = initTRPC.create();
const mockContext = { db: mockDB };
// Our mutation procedure
const createUser = t.procedure
.input(z.object({
name: z.string().min(3, "Name too short"),
email: z.string().email("Invalid email format")
}))
.mutation(async ({ input, ctx }) => {
const newUser = await ctx.db.createUser(input);
return { success: true, userId: newUser.id };
});
async function runCreateUserTest() {
console.log("--- Testing 'createUser' Mutation ---");
// Reset mock before each test (conceptual)
mockCreateUser.mockClear();
// Test Case 1: Valid input
const validInput = { name: 'Bob', email: 'bob@example.com' };
try {
const result = await createUser._def.mutation({
ctx: mockContext,
input: validInput,
path: 'createUser',
type: 'mutation'
});
console.log("Valid Input Test Result: ", JSON.stringify(result));
// Assertions: check return value and if mock was called
if (result.success && result.userId) {
console.log("Valid Input Test Passed: Mutation returned success.");
} else {
console.log("Valid Input Test Failed: Unexpected return value.");
}
// In a real test, you'd assert mockCreateUser was called with validInput
console.log(`Mock createUser called: ${mockCreateUser.mock.calls.length > 0 ? 'Yes' : 'No'}`);
if (mockCreateUser.mock.calls.length > 0 && mockCreateUser.mock.calls[0][0].name === 'Bob') {
console.log("Mock createUser was called with correct data.");
}
} catch (error: any) {
console.log("Valid Input Test Failed with error: ", error.message);
}
// Test Case 2: Invalid input (email)
mockCreateUser.mockClear(); // Clear for next test
const invalidInput = { name: 'Charlie', email: 'invalid-email' };
try {
await createUser._def.mutation({
ctx: mockContext,
input: invalidInput,
path: 'createUser',
type: 'mutation'
});
console.log("Invalid Input Test Failed: Should have thrown Zod error.");
} catch (error: any) {
console.log("Invalid Input Test Result (Expected Zod Error): ", error.message);
if (error.message.includes('Invalid email format')) {
console.log("Invalid Input Test Passed: Zod validation caught the error.");
} else {
console.log("Invalid Input Test Failed: Unexpected error message.");
}
console.log(`Mock createUser called: ${mockCreateUser.mock.calls.length > 0 ? 'Yes' : 'No'}`);
if (mockCreateUser.mock.calls.length === 0) {
console.log("Mock createUser was NOT called (as expected due to Zod error).");
}
}
}
runCreateUserTest();Petua untuk Ujian tRPC yang Berkesan
Untuk memaksimumkan nilai ujian unit anda:
- Fokus pada Pengasingan: Olok-olokkan semua kebergantungan luaran (DB, panggilan API, pengesahan).
- Uji Kes Pinggiran: Sertakan input yang sah, tidak sah dan pada sempadan.
- Nama Deskriptif: Gunakan nama ujian yang jelas dan menerangkan perkara yang diuji.
- Kecil dan Fokus: Setiap ujian sebaik-baiknya mengesahkan satu bahagian logik yang khusus.
- Buat Penegasan dengan Betul: Semak nilai yang dikembalikan serta kesan sampingan, contohnya sama ada fungsi olok-olok telah dipanggil.
Menguji Pengetahuan Anda
Semasa menguji unit prosedur mutasi tRPC yang berinteraksi dengan pangkalan data, amalan manakah yang penting untuk mengekalkan pengasingan dan keberkesanan ujian?
Ringkasan Pelajaran
Syabas! Anda telah mempelajari asas ujian unit prosedur tRPC.
- Kita membincangkan sebab ujian unit penting untuk kebolehpercayaan dan kelajuan.
- Anda melihat cara memanggil pengendali prosedur secara terus dan mengolok-olokkan objek
ctx. - Kita berlatih menguji prosedur pertanyaan dan mutasi, termasuk yang mempunyai pengesahan input Zod.
Teruskan berlatih teknik ini untuk membina API tRPC yang teguh dan mudah diselenggara!
Pelajari API tRPC Selamat Jenis dari Hujung ke Hujung dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 10
- Pelajaran
- 40
Soalan Lazim
Adakah pelajaran “Ujian Unit Prosedur tRPC” percuma?
Ya — sebanyak 3 pelajaran dalam laluan pembelajaran API tRPC Selamat Jenis dari Hujung ke Hujung, termasuk “Ujian Unit Prosedur tRPC”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus API tRPC Selamat Jenis dari Hujung ke Hujung merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Ujian Unit Prosedur tRPC”?
Pelajari cara menulis ujian unit terpencil untuk prosedur tRPC individu menggunakan rangka kerja ujian popular. Anda berlatih API tRPC Selamat Jenis dari Hujung ke Hujung menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan API tRPC Selamat Jenis dari Hujung ke Hujung?
Tiada pengalaman terdahulu diperlukan. Pembelajaran API tRPC Selamat Jenis dari Hujung ke Hujung di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 1 daripada 4.
Berapa lamakah pelajaran “Ujian Unit Prosedur tRPC” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran API tRPC Selamat Jenis dari Hujung ke Hujung ini?
Ya. Setiap pelajaran API tRPC Selamat Jenis dari Hujung ke Hujung menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Ujian Unit Prosedur tRPC
- Ujian Integrasi Penghala tRPC
- Strategi Ujian Hujung ke Hujung
- Penyamaran Konteks dan Kebergantungan dalam Pengujian tRPC