gpt4 book ai didi

typescript - 是否可以在 Jasmine 单元测试中修改或模拟 Typescript 类使用的 Inversify 容器?

转载 作者:搜寻专家 更新时间:2023-10-30 21:09:45 25 4
gpt4 key购买 nike

我有一个使用 InversifyJS 和 Inversify Inject Decorators 的 Typescript 类将服务注入(inject)私有(private)属性(property)。从功能上讲这很好,但我在弄清楚如何对其进行单元测试时遇到了问题。我在下面创建了我的问题的简化版本。

在 Jasmine 单元测试中,如何将注入(inject)的 RealDataService 替换为 FakeDataService?如果该属性不是私有(private)的,我可以创建组件并分配一个伪造的服务,但我想知道这是否可以通过使用 IOC 容器实现。

我最初关注这个this example in the InversifyJS recipes page但很快意识到他们创建的容器未在任何被测类中使用。此外,我可以在 InversifyJS 中看到的大多数代码示例文档不包括如何对其进行单元测试。

这是问题的简化版本:

我的组件.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();
}
}

dataService.ts

import { injectable } from "inversify";

export interface IDataService {
get(): string;
}

@injectable()
export class RealDataService implements IDataService {
get(): string {
return "I am real!";
}
}

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 };

单元测试

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!");
});
});

最佳答案

我能够通过从不同的文件导入容器来解决这个问题。使用此方法,您将为要注入(inject)测试的每种依赖项组合编写不同的容器。为简洁起见,假设 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 };
// 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 };
// 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!");
});
});

关于typescript - 是否可以在 Jasmine 单元测试中修改或模拟 Typescript 类使用的 Inversify 容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54830746/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com