Typescript / Node.js - 如何模拟集成测试的传递依赖?
Typescript / Node.js - How to mock transitive dependencies for integration testing?
假设我有一条由控制器处理的 Express 路线。控制器使用服务,服务使用存储库与数据源对话。
我想使用 Supertest 创建一个集成测试来测试该路由:
test -> my Express app -> controller -> service -> repository -> data source
我的问题是我需要mock repository/data 源,运行 测试!我想对一些值进行硬编码,就好像它们来自真实数据源一样。我有哪些选择?
在 Java 世界中,我会使用 Spring 或 Guice 的依赖注入,并且我会用这种方式用模拟版本替换存储库。在 Typescript/Node.js 世界中实现这种模拟的模式是什么?
我想使用普通的 Java 脚本我可以使用 Proxyquire
及其 Globally override require 功能,从测试本身模拟存储库。但我不确定这是否适用于 Typescript。
那么,使用 Typescript 和 Node.js 从测试文件中模拟 "deep" 组件(传递依赖)的推荐方法是什么?
模块在第一次加载后被缓存,所以你可以先在你的测试文件中加载它们,然后使用像 sinon 这样的库来存根它们。
考虑以下代码:
// dependency.ts
export function foo(){
return 'foo';
}
// app.ts
import {foo} from './dependency';
export default function main(){
return 'winner ' + foo();
}
您可以通过以下方式测试 app.ts 将其与 sinon 的依赖存根:
import * as Dependency from '../src/dependency';
import main from '../src/app';
describe('test dependency', () => {
var fooStub;
beforeEach(() => {
fooStub = sinon.stub(Dependency, 'foo');
fooStub.returns('la la lang');
});
afterEach(()=>{
fooStub.restore();
})
it('uses stubbed dependency', ()=>{
expect(main()).to.be.equal('winner la la lang');
});
it('can return different values on other tests', ()=>{
fooStub.returns('moonlight');
expect(main()).to.be.equal('winner moonlight');
});
});
所以基本上对于您的集成测试,您可以在启动应用程序之前导入并存根您的依赖项。我已经创建了一个 app.proxy.ts
文件:
- 在
app.proxy
中导入您的存储库并将其存根到 return 预定义数据。设置存根后,导入真正的app.ts
并导出
- 在您的集成测试文件中,导入
app.proxy
而不是应用程序并将其与超级测试一起使用。这最终会给你应用程序,但是在设置存根依赖之后!
- 编写并运行测试,知道它将使用预定义的数据
假设我有一条由控制器处理的 Express 路线。控制器使用服务,服务使用存储库与数据源对话。
我想使用 Supertest 创建一个集成测试来测试该路由:
test -> my Express app -> controller -> service -> repository -> data source
我的问题是我需要mock repository/data 源,运行 测试!我想对一些值进行硬编码,就好像它们来自真实数据源一样。我有哪些选择?
在 Java 世界中,我会使用 Spring 或 Guice 的依赖注入,并且我会用这种方式用模拟版本替换存储库。在 Typescript/Node.js 世界中实现这种模拟的模式是什么?
我想使用普通的 Java 脚本我可以使用 Proxyquire
及其 Globally override require 功能,从测试本身模拟存储库。但我不确定这是否适用于 Typescript。
那么,使用 Typescript 和 Node.js 从测试文件中模拟 "deep" 组件(传递依赖)的推荐方法是什么?
模块在第一次加载后被缓存,所以你可以先在你的测试文件中加载它们,然后使用像 sinon 这样的库来存根它们。
考虑以下代码:
// dependency.ts
export function foo(){
return 'foo';
}
// app.ts
import {foo} from './dependency';
export default function main(){
return 'winner ' + foo();
}
您可以通过以下方式测试 app.ts 将其与 sinon 的依赖存根:
import * as Dependency from '../src/dependency';
import main from '../src/app';
describe('test dependency', () => {
var fooStub;
beforeEach(() => {
fooStub = sinon.stub(Dependency, 'foo');
fooStub.returns('la la lang');
});
afterEach(()=>{
fooStub.restore();
})
it('uses stubbed dependency', ()=>{
expect(main()).to.be.equal('winner la la lang');
});
it('can return different values on other tests', ()=>{
fooStub.returns('moonlight');
expect(main()).to.be.equal('winner moonlight');
});
});
所以基本上对于您的集成测试,您可以在启动应用程序之前导入并存根您的依赖项。我已经创建了一个 app.proxy.ts
文件:
- 在
app.proxy
中导入您的存储库并将其存根到 return 预定义数据。设置存根后,导入真正的app.ts
并导出 - 在您的集成测试文件中,导入
app.proxy
而不是应用程序并将其与超级测试一起使用。这最终会给你应用程序,但是在设置存根依赖之后! - 编写并运行测试,知道它将使用预定义的数据