FG
๐Ÿ—„๏ธ Databases

Question: how to unit test without hitting the DB

Freshabout 20 hours ago
Mar 14, 20260 views
Confidence Score95%
95%

Problem

I'm trying to write some unit tests of code that uses typeorm without hitting the DB. I'm using `getRepository` in the code to do stuff. In my tests ideally I'd like to call `getRepository(SomeEntity)` and then use sinon to `sinon.mock(repository).expects('find').withArgs(...).returns(stuff)`. To avoid hitting the DB I thought I'd just not call `createConnection` if I'm in the unit tests context. However I ran into the problem that `getRepository` calls connection manager which looks if it has a connection initialized and if not throws. What would be the recommended way of handling this? Is it possible to create a "dummy" connection somehow which doesn't try to connect anywhere?

Unverified for your environment

Select your OS to check compatibility.

2 Fixes

Canonical Fix
Unverified Fix
New Fix โ€“ Awaiting Verification

Create a Mock Connection for TypeORM Unit Testing

Medium Risk

The issue arises because TypeORM's `getRepository` function checks for an active database connection. If no connection exists, it throws an error. This behavior prevents unit tests from running without hitting the actual database.

Awaiting Verification

Be the first to verify this fix

  1. 1

    Install Required Packages

    Ensure you have the necessary packages for mocking and testing. You will need 'sinon' for mocking and 'typeorm' for your entity definitions.

    bash
    npm install --save-dev sinon typeorm
  2. 2

    Create a Mock Connection

    Use TypeORM's `createConnection` method to create a mock connection that does not connect to a real database. This can be done by providing a connection options object with a 'synchronize' flag set to false.

    typescript
    import { createConnection } from 'typeorm';
    
    const mockConnection = await createConnection({
      type: 'sqlite',
      database: ':memory:',
      entities: [SomeEntity],
      synchronize: false,
      logging: false
    });
  3. 3

    Override getRepository with Mock

    In your test setup, override the `getRepository` method to return a mocked repository. Use Sinon to create a mock repository that simulates the behavior of the actual repository without hitting the database.

    typescript
    import { getRepository } from 'typeorm';
    import sinon from 'sinon';
    
    const repositoryMock = sinon.createStubInstance(SomeRepository);
    repositoryMock.find.returns(Promise.resolve(stuff));
    
    sinon.stub(typeorm, 'getRepository').returns(repositoryMock);
  4. 4

    Run Your Tests

    Execute your unit tests to ensure that they run without connecting to the database. Verify that the mocked repository methods are called as expected.

    typescript
    import { expect } from 'chai';
    
    describe('Your Test Suite', () => {
      it('should call find method', async () => {
        await yourFunction();
        expect(repositoryMock.find.called).to.be.true;
      });
    });
  5. 5

    Clean Up Mocks

    After your tests have run, restore the original `getRepository` method to avoid affecting other tests. This ensures that your testing environment remains clean.

    typescript
    afterEach(() => {
      sinon.restore();
    });

Validation

Confirm the fix by running your unit tests and ensuring they pass without any database connection errors. Check that the mocked methods are called with the expected arguments.

Sign in to verify this fix

1 low-confidence fix
Unverified Fix
New Fix โ€“ Awaiting Verification

Implement Mock Repository for TypeORM Unit Testing

Low Risk

The issue arises because TypeORM's `getRepository` method checks for an active database connection. When running unit tests, if no connection is established, it throws an error. This is problematic for unit tests that should not interact with the database.

Awaiting Verification

Be the first to verify this fix

  1. 1

    Create a Mock Connection

    Set up a mock connection that simulates TypeORM's connection manager without actually connecting to a database. This allows you to call `getRepository` without encountering errors.

    typescript
    import { createConnection, getConnection } from 'typeorm';
    import { SomeEntity } from './entities/SomeEntity';
    
    const mockConnection = async () => {
      await createConnection({
        type: 'sqlite',
        database: ':memory:',
        entities: [SomeEntity],
        synchronize: true,
        logging: false,
      });
    };
  2. 2

    Use Sinon to Mock Repository Methods

    In your unit tests, use Sinon to mock the repository methods you intend to test. This allows you to define expected behaviors without hitting the database.

    typescript
    import sinon from 'sinon';
    import { getRepository } from 'typeorm';
    
    const repository = getRepository(SomeEntity);
    const mockFind = sinon.mock(repository);
    mockFind.expects('find').withArgs({ id: 1 }).returns(Promise.resolve([{ id: 1, name: 'Test' }]));
  3. 3

    Initialize Mock Connection in Test Setup

    Ensure that the mock connection is initialized before running your tests. This can be done in a `before` hook in your test suite.

    typescript
    before(async () => {
      await mockConnection();
    });
  4. 4

    Run Your Tests

    Execute your unit tests as usual. With the mock repository in place, you should be able to test your code without hitting the actual database.

    typescript
    describe('SomeEntity Tests', () => {
      it('should find an entity by ID', async () => {
        const result = await repository.find({ id: 1 });
        expect(result).to.deep.equal([{ id: 1, name: 'Test' }]);
      });
    });

Validation

Confirm that the tests run successfully without any database connection errors. Ensure that the mocked methods return the expected results as defined in your tests.

Sign in to verify this fix

Environment

Submitted by

AC

Alex Chen

2450 rep

Tags

typeormormtypescriptdiscussioncomp:-testing