Test NestJS Service against Actual Database

I usually import AppModule for database connection, and finally after tests are executed I close the connection:

  let service: SampleService;
  let connection: Connection;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [AppModule, TypeOrmModule.forFeature([SampleEntity])],
      providers: [SampleService],
    }).compile();

    service = module.get<SampleService>(SampleService);
    connection = await module.get(getConnectionToken());
  });

  afterEach(async () => {
    await connection.close();
  });

Here's an update to the test that employs Kim Kern's suggestion.

describe("DepartmentService", () => {
  let service: DepartmentService;
  let repo: Repository<Department>;
  let module: TestingModule;

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [
        TypeOrmModule.forRoot(),
        TypeOrmModule.forFeature([Department])
      ],
      providers: [DepartmentService]
    }).compile();

    service = module.get<DepartmentService>(DepartmentService);
    repo = module.get<Repository<Department>>(getRepositoryToken(Department));
  });

  afterAll(async () => {
    module.close();
  });

  it("should be defined", () => {
    expect(service).toBeDefined();
  });

  // ...
}

To initialize typeorm properly, you should just be able to import the TypeOrmModule in your test:

Test.createTestingModule({
  imports: [
   TypeOrmModule.forRoot({
        type: 'mysql',
        // ...
   }),
   TypeOrmModule.forFeature([Department])
  ]

I prefer not using @nestjs/testing for the sake of simplicity.

First of all, create a reusable helper:

/* src/utils/testing-helpers/createMemDB.js */
import { createConnection, EntitySchema } from 'typeorm'
type Entity = Function | string | EntitySchema<any>

export async function createMemDB(entities: Entity[]) {
  return createConnection({
    // name, // let TypeORM manage the connections
    type: 'sqlite',
    database: ':memory:',
    entities,
    dropSchema: true,
    synchronize: true,
    logging: false
  })
}

Then, write test:

/* src/user/user.service.spec.ts */
import { Connection, Repository } from 'typeorm'
import { createMemDB } from '../utils/testing-helpers/createMemDB'
import UserService from './user.service'
import User from './user.entity'

describe('User Service', () => {
  let db: Connection
  let userService: UserService
  let userRepository: Repository<User>

  beforeAll(async () => {
    db = await createMemDB([User])
    userRepository = await db.getRepository(User)
    userService = new UserService(userRepository) // <--- manually inject
  })
  afterAll(() => db.close())

  it('should create a new user', async () => {
    const username = 'HelloWorld'
    const password = 'password'

    const newUser = await userService.createUser({ username, password })
    expect(newUser.id).toBeDefined()

    const newUserInDB = await userRepository.findOne(newUser.id)
    expect(newUserInDB.username).toBe(username)
  })
})

Refer to https://github.com/typeorm/typeorm/issues/1267#issuecomment-483775861