You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Testcontainers的Jest数据库测试无法终止问题求助

Node.js(TypeScript) + Postgres 15 + Testcontainers 测试无法终止问题

我正在为Node.js(TypeScript)应用的数据库编写测试,使用Postgres 15和Testcontainers。手动运行代码正常,数据库客户端已正确释放,但测试始终无法终止。

要测试的createUser方法会调用getUserById,后者又会调用getTagsByUserId,相关代码如下:

async createUser(user: User): Promise<User> {
    let client: PoolClient | undefined
    try {
        client = await DatabaseConnection.getClient()
        await client.query('BEGIN')
        const res = await client.query(this.CREATE_USER_QUERY, [user.username, user.password, user.nickname, user.email, user.dateOfBirth, user.pending])
        const userId = res.rows[0].user_id
        user.userId = userId
        if (user.tags) {
            for (const tag of user.tags) {
                await client.query(this.CREATE_TAGS_QUERY, [userId, tag.toString()])
            }
        }
        await client.query('COMMIT')
        return await this.getUserById(userId)
    } catch (e) {
        if (client) await client.query('ROLLBACK')
        throw e
    } finally {
        if (client) await client.release()
    }
}


async getUserById(userId: string): Promise<User> {
    let client: PoolClient | undefined
    try {
        client = await DatabaseConnection.getClient()
        const res = await client.query(this.SELECT_USER_BY_ID_QUERY, [userId])
        const user: User = {
            dateOfBirth: res.rows[0].date_of_birth,
            email: res.rows[0].email,
            nickname: res.rows[0].nickname,
            password: res.rows[0].password,
            pending: res.rows[0].pending,
            private: res.rows[0].private,
            tags: [],
            userId: res.rows[0].user_id,
            username: res.rows[0].username
        }
        user.tags = await this.getTagsByUserId(userId)
        return user
    } catch (e) {
        throw e
    } finally {
        if (client) await client.release()
    }
}

private async getTagsByUserId(userId: string): Promise<Tag[]> {
    let client: PoolClient | undefined
    try {
        client = await DatabaseConnection.getClient()
        const res = await client.query(this.GET_TAGS_QUERY, [userId])
        return res.rows.map(row => row.user_tag)
    } catch (e) {
        throw e
    } finally {
        if (client) await client.release()
    }
}

DatabaseConnection中维护了一个Client Pool,getClient方法从池中获取客户端。

测试代码如下:

import {UsersRepository} from "../../main/repository/users.repository";
import {Tag, User} from "../../main/schema/types";
import {Pool, PoolClient} from "pg";
import {
    TestContainer,
    StartedTestContainer,
    PostgreSqlContainer, Wait, StartedPostgreSqlContainer
} from "testcontainers";
import {DatabaseConnection} from "../../main/repository/DatabaseConnection";

const fs = require('fs')

jest.useFakeTimers()

const initSqlScript = fs.readFileSync('./sql/init.sql').toString()


describe('User Repository tests', () => {

    const port: number = process.env.DB_PORT ? +process.env.DB_PORT : 5432
    let pool: Pool
    let container: StartedPostgreSqlContainer

    beforeAll(async () => {
        container = await new PostgreSqlContainer("postgres:15")
            .withDatabase(process.env.POSTGRES_DB || 'test')
            .withUsername(process.env.POSTGRES_USER || 'test')
            .withPassword(process.env.POSTGRES_PASSWORD || 'test')
            .withExposedPorts(port)
            .start();
        pool = new Pool({connectionString: container.getConnectionUri()})
        const client = await pool.connect()
        await client.query(initSqlScript) // initializes my database
        await client.release()
        await DatabaseConnection.changeConnection(container.getConnectionUri()) // sets the connection for my DatabaseConnection to the test container
    })

    const userRepository = new UsersRepository()

    const originalUser: User = {
        dateOfBirth: "01-01-2000",
        email: "test",
        nickname: "test",
        password: "test",
        username: "test",
        pending: true
    }

    afterEach(async () => {
        await userRepository.clear()
    })

    it('should create a user in DB and return user with ID', async () => {
        const createdUser = await userRepository.createUser(originalUser)
        expect(createdUser.username).toBe(originalUser.username);
        expect(createdUser.email).toBe(originalUser.email);
        expect(createdUser.nickname).toBe(originalUser.nickname);
        expect(createdUser.password).toBe(originalUser.password);
        expect(createdUser.dateOfBirth).toBe(originalUser.dateOfBirth);
        expect(createdUser.pending).toBe(originalUser.pending);
        expect(typeof createdUser.userId).toBe("string")
    });
})

运行测试时,数据库中已成功创建用户,但测试无法终止。我尝试直接返回输入的用户对象而非查询数据库,问题依然存在。
日志显示连接池仅1个空闲连接,无活跃连接,调试确认所有客户端均已释放。使用本地数据库时测试可正常终止,但我希望使用Testcontainers。


内容的提问来源于stack exchange,提问作者Julia Mayrhauser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:42:36