我似乎无法在我的规范文件中正确模拟导入,并且我想知道是否有人可以看到我所缺少的内容。
这是我的数据库连接的导出类
import Knex from 'knex';
import { merge } from 'lodash';
import knexfile from '../knexfile';
class Database {
private knexInstance: Knex;
private config: object;
connect(options = {}): void {
if (this.knexInstance) {
return;
}
this.config = merge({}, knexfile, options);
this.knexInstance = Knex(this.config);
}
get query(): Knex {
if (!this.knexInstance) {
this.connect();
}
return this.knexInstance;
}
close(done): void {
if (!this.knexInstance) {
done();
return;
}
this.knexInstance.destroy(done);
}
}
export default new Database();
这里是试图使用数据库文件的操作文件。
import db from '../../database';
const tableName = 'attempts';
export const typeDef = `
extend type Query {
attempt(id: String): Attempt!
}
extend type Mutation {
createAttempt(questionId: String!, attemptId: String!, choiceId: String): Attempt
}
type Attempt {
id: String!
correctanswers: Int!
userid: String!
examid: String!
}
`;
export const resolvers = {
Query: {
attempt(_, { id = '' }) {
return db
.query(tableName)
.where({ id })
.first();
},
},
Mutation: {
async createAttempt(root, args) {
const [answer] = await db
.query(tableName)
.insert(args)
.returning('*');
return answer;
},
},
};
这是我的测试文件。
import { createSandbox } from 'sinon';
import { resolvers } from './answer';
import db from '../../database';
import * as should from 'should';
const sandbox = createSandbox();
describe('Answer', () => {
afterEach(() => sandbox.restore());
describe('Query Answer', () => {
it('should return answer by id', async () => {
const expected = { id: 'xxx' };
const firstSpy = sandbox.fake.resolves(expected);
const whereSpy = sandbox.fake.resolves({
first: firstSpy,
});
// This stub never seems to get called. It doesn't look like the import is ever being replaced with the stub in the implementation file.
const querySpy = sandbox.stub(db, 'query').callsFake(() => {
return Promise.resolve({
where: whereSpy,
});
});
const inputId = '100';
const result = await resolvers.Query.answer(null, { id: inputId });
sandbox.assert.calledOnce(querySpy);
sandbox.assert.calledOnce(whereSpy);
sandbox.assert.calledOnce(firstSpy);
result.should.deepEqual(expected);
});
});
});
[当我运行测试时,导入文件似乎并没有被实现文件中的存根替换,我也不知道为什么。
有两个警告:
当您从测试文件和GraphQL解析器文件中的db
文件导入database.ts
时,它们是不同的实例。因此,即使您在测试文件中存根db
实例的方法。解析程序仍将db
实例与原始方法一起使用(未存根)。存在潜在的风险。
在GraphQL解析器中使用依赖项的最佳实践是根据解析器db
参数传递依赖项(您的案例的context
实例)。因为它是某种依赖注入,所以它使代码更易于测试。
例如
answer.ts
:
const tableName = "attempts";
export const typeDef = `
extend type Query {
attempt(id: String): Attempt!
}
extend type Mutation {
createAttempt(questionId: String!, attemptId: String!, choiceId: String): Attempt
}
type Attempt {
id: String!
correctanswers: Int!
userid: String!
examid: String!
}
`;
export const resolvers = {
Query: {
attempt(_, { id = "" }, { db }) {
return db
.query(tableName)
.where({ id })
.first();
},
},
Mutation: {
async createAttempt(root, args, { db }) {
const [answer] = await db
.query(tableName)
.insert(args)
.returning("*");
return answer;
},
},
};
anwser.test.ts
:
import sinon from "sinon";
import { resolvers } from "./answer";
import { expect } from "chai";
describe("Answer", () => {
describe("Query Answer", () => {
it("should return answer by id", async () => {
const expected = { id: "xxx" };
const inputId = "100";
const knexInstanceStub = {
query: sinon.stub().returnsThis(),
where: sinon.stub().returnsThis(),
first: sinon.stub().resolves(expected),
};
const result = await resolvers.Query.attempt(null, { id: inputId }, { db: knexInstanceStub });
sinon.assert.calledOnce(knexInstanceStub.query);
sinon.assert.calledOnce(knexInstanceStub.where);
sinon.assert.calledOnce(knexInstanceStub.first);
expect(result).to.be.deep.eq(expected);
});
});
});
我们甚至不需要导入db
并将其存根。我们可以创建一个存根db
并将其传递到解析程序的上下文。
带有覆盖率报告的单元测试结果:
Answer
Query Answer
✓ should return answer by id
1 passing (11ms)
----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------------|----------|----------|----------|----------|-------------------|
All files | 84.62 | 33.33 | 80 | 86.36 | |
answer.test.ts | 100 | 100 | 100 | 100 | |
answer.ts | 60 | 33.33 | 50 | 62.5 | 30,31,36 |
----------------|----------|----------|----------|----------|-------------------|