In-memory SQLite untuk testing: setup test database dengan better-sqlite3 dan :memory:, membuat test database setup helper, unit testing queries untuk memvalidasi output, dan integration testing full request cycle dari API route hingga Drizzle query dan response.

Setelah di episode 17 kita mempelajari Database Drivers & Serverless — pilihan driver untuk setiap database dan platform — pada episode ini kita membahas testing: bagaimana menguji queries dan integrasi Drizzle ORM menggunakan SQLite in-memory.
Testing adalah bagian kritis dari development cycle. In-memory SQLite memberikan test database yang cepat, isolasi, dan tidak membutuhkan database external.
import Database from 'better-sqlite3'
import { drizzle } from 'drizzle-orm/better-sqlite3'
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core'
const sqlite = new Database(':memory:')
const db = drizzle(sqlite)SQLite in-memory sangat cepat — database dibuat dan dihancurkan di setiap test run.
sqlite.exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
age INTEGER
)
`)import Database from 'better-sqlite3'
import { drizzle } from 'drizzle-orm/better-sqlite3'
import { sql } from 'drizzle-orm'
export function createTestDb() {
const sqlite = new Database(':memory:')
const db = drizzle(sqlite)
// Create tables
sqlite.exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
age INTEGER
)
`)
return db
}
export async function clearDb(db: ReturnType<typeof createTestDb>) {
await db.execute(sql`DELETE FROM users`)
}import { describe, it, expect, beforeEach } from 'vitest'
import { createTestDb, clearDb } from './test-helpers'
import { users } from './schema'
import { eq } from 'drizzle-orm'
describe('User queries', () => {
let db: ReturnType<typeof createTestDb>
beforeEach(async () => {
db = createTestDb()
await db.insert(users).values([
{ name: 'John', email: 'john@example.com', age: 25 },
{ name: 'Jane', email: 'jane@example.com', age: 30 },
])
})
it('should find user by email', async () => {
const result = await db.select().from(users)
.where(eq(users.email, 'john@example.com'))
expect(result).toHaveLength(1)
expect(result[0].name).toBe('John')
})
it('should return all users', async () => {
const result = await db.select().from(users)
expect(result).toHaveLength(2)
})
})import { describe, it, expect } from 'vitest'
import { createTestDb } from './test-helpers'
import { users } from './schema'
async function getUserHandler(db: any, userId: number) {
const result = await db.select().from(users).where(eq(users.id, userId))
return result[0] || null
}
describe('getUser API', () => {
it('should return user by id', async () => {
const db = createTestDb()
await db.insert(users).values({ name: 'John', email: 'john@example.com' })
const user = await getUserHandler(db, 1)
expect(user).not.toBeNull()
expect(user.name).toBe('John')
})
it('should return null for non-existent user', async () => {
const db = createTestDb()
const user = await getUserHandler(db, 999)
expect(user).toBeNull()
})
})Tip
In-memory SQLite cocok untuk testing queries yang tidak menggunakan fitur PostgreSQL spesifik (RETURNING, JSON, array). Untuk testing fitur PostgreSQL, pertimbangkan menggunakan testcontainers atau database terpisah.
Pada episode 18 ini, kalian telah memahami Testing dengan In-Memory SQLite:
:memory:) untuk test database yang cepat dan isolasi.Di episode 19 selanjutnya kita akan mempelajari Project Structure & Scalability — struktur folder yang baik untuk proyek kecil-sedang, modular schema, query service pattern, dan scaling ke microservices. Sampai jumpa di episode 19!