Jest数据库测试未与testcontainers终止。

huangapple go评论95阅读模式
英文:

Jest database test not terminating with testcontainers

问题

I am trying to test my database in my Node application (Typescript). I am using Postgres 15 and Testcontainers to test my database. My code works fine manually and my clients are being released, but for some reason my tests don't terminate.

I want to test the createUser method which uses getUserById, which also uses getTagsByUserId.

In DatabaseConnection I have a Client Pool. With getClient I return a Client from the pool.

This is my test:

  1. import { UsersRepository } from "../../main/repository/users.repository";
  2. import { Tag, User } from "../../main/schema/types";
  3. import { Pool, PoolClient } from "pg";
  4. import {
  5. TestContainer,
  6. StartedTestContainer,
  7. PostgreSqlContainer, Wait, StartedPostgreSqlContainer
  8. } from "testcontainers";
  9. import { DatabaseConnection } from "../../main/repository/DatabaseConnection";
  10. const fs = require('fs')
  11. jest.useFakeTimers()
  12. const initSqlScript = fs.readFileSync('./sql/init.sql').toString()
  13. describe('User Repository tests', () => {
  14. const port: number = process.env.DB_PORT ? +process.env.DB_PORT : 5432
  15. let pool: Pool
  16. let container: StartedPostgreSqlContainer
  17. beforeAll(async () => {
  18. container = await new PostgreSqlContainer("postgres:15")
  19. .withDatabase(process.env.POSTGRES_DB || 'test')
  20. .withUsername(process.env.POSTGRES_USER || 'test')
  21. .withPassword(process.env.POSTGRES_PASSWORD || 'test')
  22. .withExposedPorts(port)
  23. .start();
  24. pool = new Pool({connectionString: container.getConnectionUri()})
  25. const client = await pool.connect()
  26. await client.query(initSqlScript) // initializes my database
  27. await client.release()
  28. await DatabaseConnection.changeConnection(container.getConnectionUri()) // sets the connection for my DatabaseConnection to the test container
  29. })
  30. const userRepository = new UsersRepository()
  31. const originalUser: User = {
  32. dateOfBirth: "01-01-2000",
  33. email: "test",
  34. nickname: "test",
  35. password: "test",
  36. username: "test",
  37. pending: true
  38. }
  39. afterEach(async () => {
  40. await userRepository.clear()
  41. })
  42. it('should create a user in DB and return user with ID', async () => {
  43. const createdUser = await userRepository.createUser(originalUser)
  44. expect(createdUser.username).toBe(originalUser.username);
  45. expect(createdUser.email).toBe(originalUser.email);
  46. expect(createdUser.nickname).toBe(originalUser.nickname);
  47. expect(createdUser.password).toBe(originalUser.password);
  48. expect(createdUser.dateOfBirth).toBe(originalUser.dateOfBirth);
  49. expect(createdUser.pending).toBe(originalUser.pending);
  50. expect(typeof createdUser.userId).toBe("string")
  51. });
  52. })

However, when I run my test, it does not terminate. I have checked the database and the user is created. I have also tried just returning the user object I have as input instead of getting the user from the database, but that also does not work.

I am logging any connections to my pool and it only says 1 idle connection and no active connections. When debugging, all of my clients are released.

Also, it works when I just use my local database, but I don't want that.

英文:

I am trying to test my database in my Node application (Typescript). I am using Postgres 15 and Testcontainers to test my database. My code works fine manually and my clients are being released, but for some reason my tests don't terminate.

I want to test the createUser method which uses getUserById, which also uses getTagsByUserId.

  1. async createUser(user: User): Promise<User> {
  2. let client: PoolClient | undefined
  3. try {
  4. client = await DatabaseConnection.getClient()
  5. await client.query('BEGIN')
  6. const res = await client.query(this.CREATE_USER_QUERY, [user.username, user.password, user.nickname, user.email, user.dateOfBirth, user.pending])
  7. const userId = res.rows[0].user_id
  8. user.userId = userId
  9. if (user.tags) {
  10. for (const tag of user.tags) {
  11. await client.query(this.CREATE_TAGS_QUERY, [userId, tag.toString()])
  12. }
  13. }
  14. await client.query('COMMIT')
  15. return await this.getUserById(userId)
  16. } catch (e) {
  17. if (client) await client.query('ROLLBACK')
  18. throw e
  19. } finally {
  20. if (client) await client.release()
  21. }
  22. }
  23. async getUserById(userId: string): Promise<User> {
  24. let client: PoolClient | undefined
  25. try {
  26. client = await DatabaseConnection.getClient()
  27. const res = await client.query(this.SELECT_USER_BY_ID_QUERY, [userId])
  28. const user: User = {
  29. dateOfBirth: res.rows[0].date_of_birth,
  30. email: res.rows[0].email,
  31. nickname: res.rows[0].nickname,
  32. password: res.rows[0].password,
  33. pending: res.rows[0].pending,
  34. private: res.rows[0].private,
  35. tags: [],
  36. userId: res.rows[0].user_id,
  37. username: res.rows[0].username
  38. }
  39. user.tags = await this.getTagsByUserId(userId)
  40. return user
  41. } catch (e) {
  42. throw e
  43. } finally {
  44. if (client) await client.release()
  45. }
  46. }
  47. private async getTagsByUserId(userId: string): Promise<Tag[]> {
  48. let client: PoolClient | undefined
  49. try {
  50. client = await DatabaseConnection.getClient()
  51. const res = await client.query(this.GET_TAGS_QUERY, [userId])
  52. return res.rows.map(row => row.user_tag)
  53. } catch (e) {
  54. throw e
  55. } finally {
  56. if (client) await client.release()
  57. }
  58. }

In DatabaseConnection I have a Client Pool. With getClient i return a Client from the pool.

This is my test:

  1. import {UsersRepository} from "../../main/repository/users.repository";
  2. import {Tag, User} from "../../main/schema/types";
  3. import {Pool, PoolClient} from "pg";
  4. import {
  5. TestContainer,
  6. StartedTestContainer,
  7. PostgreSqlContainer, Wait, StartedPostgreSqlContainer
  8. } from "testcontainers";
  9. import {DatabaseConnection} from "../../main/repository/DatabaseConnection";
  10. const fs = require('fs')
  11. jest.useFakeTimers()
  12. const initSqlScript = fs.readFileSync('./sql/init.sql').toString()
  13. describe('User Repository tests', () => {
  14. const port: number = process.env.DB_PORT ? +process.env.DB_PORT : 5432
  15. let pool: Pool
  16. let container: StartedPostgreSqlContainer
  17. beforeAll(async () => {
  18. container = await new PostgreSqlContainer("postgres:15")
  19. .withDatabase(process.env.POSTGRES_DB || 'test')
  20. .withUsername(process.env.POSTGRES_USER || 'test')
  21. .withPassword(process.env.POSTGRES_PASSWORD || 'test')
  22. .withExposedPorts(port)
  23. .start();
  24. pool = new Pool({connectionString: container.getConnectionUri()})
  25. const client = await pool.connect()
  26. await client.query(initSqlScript) // initializes my database
  27. await client.release()
  28. await DatabaseConnection.changeConnection(container.getConnectionUri()) // sets the connection for my DatabaseConnection to the test container
  29. })
  30. const userRepository = new UsersRepository()
  31. const originalUser: User = {
  32. dateOfBirth: "01-01-2000",
  33. email: "test",
  34. nickname: "test",
  35. password: "test",
  36. username: "test",
  37. pending: true
  38. }
  39. afterEach(async () => {
  40. await userRepository.clear()
  41. })
  42. it('should create a user in DB and return user with ID', async () => {
  43. const createdUser = await userRepository.createUser(originalUser)
  44. expect(createdUser.username).toBe(originalUser.username);
  45. expect(createdUser.email).toBe(originalUser.email);
  46. expect(createdUser.nickname).toBe(originalUser.nickname);
  47. expect(createdUser.password).toBe(originalUser.password);
  48. expect(createdUser.dateOfBirth).toBe(originalUser.dateOfBirth);
  49. expect(createdUser.pending).toBe(originalUser.pending);
  50. expect(typeof createdUser.userId).toBe("string")
  51. });
  52. })

However, when i run my test, it does not terminate. I have checked the database and the user is created. I have also tried just returning the user object i have as input instead of getting the user from the database, but that also does not work.

I am logging any connections to my pool and it only says 1 idle connection and no active connections. When debugging, all of my clients are released.

Also, it works when I just use my local database, but I don't want that.

答案1

得分: 0

我自己找到了解决方法!我配置了Jest来使用虚拟计时器,因为我在某处读到这样做可以帮助处理超时异常。我不知道这正是导致问题的原因!

英文:

Ok so I figured it out on my own! I configured Jest to use fake timers because I read somewhere that this would help with timeout exceptions. Little did I know that this was causing my problems!

huangapple
  • 本文由 发表于 2023年4月17日 02:26:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76029606.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定