I would like to be able to test my Nest service against an actual database. I understand that most unit tests should use a mock object, but it also, at times, makes sense to test against the database itself.
I have searched through SO and the GH issues for Nest, and am starting to reach the transitive closure of all answers. :-)
I am trying to work from https://github.com/nestjs/nest/issues/363#issuecomment-360105413. Following is my Unit test, which uses a custom provider to pass the repository to my service class.
describe("DepartmentService", () => {
const token = getRepositoryToken(Department);
let service: DepartmentService;
let repo: Repository<Department>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
DepartmentService,
{
provide: token,
useClass: Repository
}
]
}).compile();
service = module.get<DepartmentService>(DepartmentService);
repo = module.get(token);
});
Everything compiles properly, TypeScript seems happy. However, when I try to execute create
or save
on my Repository
instance, the underlying Repository
appears to be undefined. Here's the stack backtrace:
TypeError: Cannot read property 'create' of undefined
at Repository.Object.<anonymous>.Repository.create (repository/Repository.ts:99:29)
at DepartmentService.<anonymous> (relational/department/department.service.ts:46:53)
at relational/department/department.service.ts:19:71
at Object.<anonymous>.__awaiter (relational/department/department.service.ts:15:12)
at DepartmentService.addDepartment (relational/department/department.service.ts:56:16)
at Object.<anonymous> (relational/department/test/department.service.spec.ts:46:35)
at relational/department/test/department.service.spec.ts:7:71
It appears that the EntityManager
instance with the TypeORM Repository
class is not being initialized; it is the undefined
reference that this backtrace is complaining about.
How do I get the Repository
and EntityManager
to initialize properly?
thanks, tom.
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
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();
});
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With