Gav*_*and 5 unit-testing jasmine typescript inversifyjs
我有一个 Typescript 类,它使用 InversifyJS 和Inversify Inject Decorators将服务注入私有属性。从功能上讲,这很好,但我在弄清楚如何对其进行单元测试时遇到了问题。我在下面创建了我的问题的简化版本。
在 Jasmine 单元测试中,如何用 替换注入RealDataService的FakeDataService?如果该属性不是私有的,我可以创建该组件并分配一个假服务,但我想知道这是否可以通过使用 IOC 容器来实现。
我最初在 InversifyJS 食谱页面中遵循了这个示例,但很快意识到他们创建的容器没有在任何被测试的类中使用。另外,我在InversifyJS文档中看到的大多数代码示例都没有介绍如何对其进行单元测试。
这是问题的简化版本:
myComponent.ts
import { lazyInject, Types } from "./ioc";
import { IDataService } from "./dataService";
export default class MyComponent {
@lazyInject(Types.IDataService)
private myDataService!: IDataService;
getSomething(): string {
return this.myDataService.get();
}
}
Run Code Online (Sandbox Code Playgroud)
数据服务.ts
import { injectable } from "inversify";
export interface IDataService {
get(): string;
}
@injectable()
export class RealDataService implements IDataService {
get(): string {
return "I am real!";
}
}
Run Code Online (Sandbox Code Playgroud)
IOC配置
import "reflect-metadata";
import { Container, ContainerModule, interfaces, BindingScopeEnum } from "inversify";
import getDecorators from "inversify-inject-decorators";
import { IDataService, RealDataService } from "./dataService";
const Types = {
IDataService: Symbol.for("IDataService")
};
const iocContainerModule = new ContainerModule((bind: interfaces.Bind) => {
bind<IDataService>(Types.IDataService).to(RealDataService);
});
const iocContainer = new Container();
iocContainer.load(iocContainerModule);
const { lazyInject } = getDecorators(iocContainer);
export { lazyInject, Types };
Run Code Online (Sandbox Code Playgroud)
单元测试
import { Container } from "inversify";
import { Types } from "./ioc";
import MyComponent from "./myComponent";
import { IDataService } from "./dataService";
class FakeDataService implements IDataService {
get(): string {
return "I am fake!";
}
}
describe("My Component", () => {
let iocContainer!: Container;
let myComponent!: MyComponent;
beforeEach(() => {
iocContainer = new Container();
iocContainer.bind(Types.IDataService).to(FakeDataService);
// How do I make myComponent use this iocContainer?
// Is it even possible?
myComponent = new MyComponent();
});
it("should use the mocked service", () => {
const val = myComponent.getSomething();
expect(val).toBe("I am fake!");
});
});
Run Code Online (Sandbox Code Playgroud)
小智 4
我能够通过从不同的文件导入容器来解决这个问题。使用此方法,您可以为要注入测试的每个依赖项组合编写一个不同的容器。为了简洁起见,假设 Inversify 文档给出的忍者武士的代码示例。
// src/inversify.prod-config.ts
import "reflect-metadata";
import { Container } from "inversify";
import { TYPES } from "./types";
import { Warrior, Weapon, ThrowableWeapon } from "./interfaces";
import { Ninja, Katana, Shuriken } from "./entities";
const myContainer = new Container();
myContainer.bind<Warrior>(TYPES.Warrior).to(Ninja);
myContainer.bind<Weapon>(TYPES.Weapon).to(Katana);
myContainer.bind<ThrowableWeapon>(TYPES.ThrowableWeapon).to(Shuriken);
export { myContainer };
Run Code Online (Sandbox Code Playgroud)
// test/fixtures/inversify.unit-config.ts
import "reflect-metadata";
import {Container, inject, injectable} from "inversify";
import { TYPES } from "../../src/types";
import { Warrior, Weapon, ThrowableWeapon } from "../../src/interfaces";
// instead of importing the injectable classes from src,
// import mocked injectables from a set of text fixtures.
// For brevity, I defined mocks inline here, but you would
// likely want these in their own files.
@injectable()
class TestKatana implements Weapon {
public hit() {
return "TEST cut!";
}
}
@injectable()
class TestShuriken implements ThrowableWeapon {
public throw() {
return "TEST hit!";
}
}
@injectable()
class TestNinja implements Warrior {
private _katana: Weapon;
private _shuriken: ThrowableWeapon;
public constructor(
@inject(TYPES.Weapon) katana: Weapon,
@inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); }
public sneak() { return this._shuriken.throw(); }
}
const myContainer = new Container();
myContainer.bind<Warrior>(TYPES.Warrior).to(TestNinja);
myContainer.bind<Weapon>(TYPES.Weapon).to(TestKatana);
myContainer.bind<ThrowableWeapon>(TYPES.ThrowableWeapon).to(TestShuriken);
export { myContainer };
Run Code Online (Sandbox Code Playgroud)
// test/unit/example.test.ts
// Disclaimer: this is a Jest test, but a port to jasmine should look similar.
import {myContainer} from "../fixtures/inversify.unit-config";
import {Warrior} from "../../../src/interfaces";
import {TYPES} from "../../../src/types";
describe('test', () => {
let ninja;
beforeEach(() => {
ninja = myContainer.get<Warrior>(TYPES.Warrior);
});
test('should pass', () => {
expect(ninja.fight()).toEqual("TEST cut!");
expect(ninja.sneak()).toEqual("TEST hit!");
});
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12849 次 |
| 最近记录: |