Mock TypeORM Package

References

Mock TypeORM Package
Mock TypeORM Package Documentation

In the last couple of months, I have been working extensively with TypeORM and built many projects using this ORM. Setting up a test database for my unit tests was quite c…


This content originally appeared on DEV Community and was authored by Jazim Abbas

References

  1. Mock TypeORM Package
  2. Mock TypeORM Package Documentation

In the last couple of months, I have been working extensively with TypeORM and built many projects using this ORM. Setting up a test database for my unit tests was quite challenging. To overcome this, I mocked TypeORM methods to avoid interacting with a real database. However, I found myself copying the same mock code into every new project repeatedly.

To streamline this process and help others facing the same issue, I decided to create a package. Initially, I mocked all the TypeORM code using Vitest, but that only worked in the Vitest environment. Since many developers use different testing frameworks such as Jest, Mocha, etc., I needed a more versatile solution. Hence, I used Sinon for mocking TypeORM, which is compatible with various testing frameworks. Although Sinon is excellent, I still have a soft spot for Vitest.

Installation

This package is built using TypeScript, so you’ll get type safety out of the box. I have also added thorough unit tests, which you can refer to for better understanding and reference.

To install this package, use the following command:

npm install --save-dev mock-typeorm sinon @types/sinon

That’s pretty much it! Now you can use this package to mock your TypeORM calls. Note that Sinon is added as a peer dependency, so you need to install it as well.

Key Concepts

Here’s how you can mock TypeORM calls. Use the following snippet:

import { MockTypeORM } from 'mock-typeorm'

test('abc', () => {
  new MockTypeORM()
})

By just doing this, you prevent any interaction with your database. This is the magic of mocking.

Reset or Restore Mock State

After each test, you need to clear the mock state so that other tests cannot use the mock state of previous tests. Otherwise, you’ll get some strange results. To reset the state, you have different methods:

Method 1: Create an instance for each test

import Sinon from 'sinon'
import { MockTypeORM } from 'mock-typeorm'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'

describe('tests suite', () => {
  let typeorm: MockTypeORM

  beforeEach(() => {
    typeorm = new MockTypeORM()
  })

  afterEach(() => {
    typeorm.restore()
    // you can also do this instead - Sinon.restore()
    // Sinon.restore();
  })

  it('first test', async () => {
    const mockUsers = ['user']
    typeorm.onMock('User').toReturn(mockUsers, 'find')

    const users = await dataSource.getRepository(User).find()

    expect(users).toEqual(mockUsers)
  })

  it('second test', async () => {
    const mockUsers = []
    typeorm.onMock('User').toReturn(mockUsers, 'find')

    const users = await dataSource.getRepository(User).find()

    expect(users).toEqual(mockUsers)
  })
})

In this approach, using hooks provided by Vitest (or similar hooks from other testing libraries), we create a new MockTypeORM object in the beforeEach hook and restore TypeORM to its original state in the afterEach hook.

Method 2: Single Instance

import Sinon from 'sinon'
import { MockTypeORM } from 'mock-typeorm'
import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'

describe('tests suite', () => {
  let typeorm: MockTypeORM

  beforeAll(() => {
    typeorm = new MockTypeORM()
  })

  afterEach(() => {
    typeorm.resetAll()
  })

  afterAll(() => {
    typeorm.restore()
  })

  it('first test', async () => {
    const mockUsers = ['user']
    typeorm.onMock('User').toReturn(mockUsers, 'find')

    const users = await dataSource.getRepository(User).find()

    expect(users).toEqual(mockUsers)
  })

  it('second test', async () => {
    const mockUsers = []
    typeorm.onMock('User').toReturn(mockUsers, 'find')

    const users = await dataSource.getRepository(User).find()

    expect(users).toEqual(mockUsers)
  })
})

In this approach, we create a MockTypeORM instance once before all tests start and reset the mock state after each test. After all tests, we restore TypeORM to its original behavior.

Mocking - Fun Stuff

Now that you understand how mocking works and how to restore it to its original behavior, let's see how to mock actual methods like find(), findOne(), save(), etc.

Example

describe('test suites', () => {
  it('test', async () => {
    const typeorm = new MockTypeORM()
    typeorm.onMock(User).toReturn(['user'], 'find')

    const userRepo = dataSource.getRepository(User)
    const users = await userRepo.find()

    expect(users).toEqual(['user'])
  })
})

Helper Functions

  • onMock()
  • resetAll()
  • restore()

onMock()

onMock() accepts a repository class or string (repository name). This is useful when using EntitySchema in JavaScript.

const typeorm = new MockTypeORM()
typeorm.onMock(User) // repository class
typeorm.onMock('User') // repository name as string

onMock() returns this to allow method chaining:

typeorm.onMock(User).toReturn([], 'find').toReturn({ id: '1' }, 'findOne')

reset()

onMock() also returns a reset() method to reset mock data:

describe('test suites', () => {
  it('test', async () => {
    const typeorm = new MockTypeORM()
    typeorm.onMock(User).toReturn(['user'], 'find').reset('find')

    const userRepo = dataSource.getRepository(User)
    const users = await userRepo.find()

    expect(users).toEqual({})
  })
})

As you can see, I reset the mock data for the find method that we set using the toReturn() function. So when the find() method is called and no mock data is found for that method, it will return {} by default. That’s what we are expecting in our test assertion, meaning we have successfully reset the find method.

To reset everything at the repository level:

describe('test suites', () => {
  it('test', async () => {
    const typeorm = new MockTypeORM()
    typeorm
      .onMock(User)
      .toReturn(['user'], 'find')
      .toReturn({ id: '1' }, 'findOne')
      .reset()

    const userRepo = dataSource.getRepository(User)
    const users = await userRepo.find()
    const user = await userRepo.findOne({})

    expect(users).toEqual({})
    expect(user).toEqual({})
  })
})

If you find this package useful please stare this my github repository and share with other developers.

Happy Coding!


This content originally appeared on DEV Community and was authored by Jazim Abbas


Print Share Comment Cite Upload Translate Updates
APA

Jazim Abbas | Sciencx (2024-06-26T07:49:38+00:00) Mock TypeORM Package. Retrieved from https://www.scien.cx/2024/06/26/mock-typeorm-package/

MLA
" » Mock TypeORM Package." Jazim Abbas | Sciencx - Wednesday June 26, 2024, https://www.scien.cx/2024/06/26/mock-typeorm-package/
HARVARD
Jazim Abbas | Sciencx Wednesday June 26, 2024 » Mock TypeORM Package., viewed ,<https://www.scien.cx/2024/06/26/mock-typeorm-package/>
VANCOUVER
Jazim Abbas | Sciencx - » Mock TypeORM Package. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/06/26/mock-typeorm-package/
CHICAGO
" » Mock TypeORM Package." Jazim Abbas | Sciencx - Accessed . https://www.scien.cx/2024/06/26/mock-typeorm-package/
IEEE
" » Mock TypeORM Package." Jazim Abbas | Sciencx [Online]. Available: https://www.scien.cx/2024/06/26/mock-typeorm-package/. [Accessed: ]
rf:citation
» Mock TypeORM Package | Jazim Abbas | Sciencx | https://www.scien.cx/2024/06/26/mock-typeorm-package/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.