TypeScriptでTDDを実行する可能性を検討しています。 TypeScriptでテストを作成する場合、インポートステートメントでテスト中のクラスのモックを返すことは可能ですか?または、純粋なJavaScriptでテストを記述し、AMDを自分で注入することを処理する唯一の実行可能なアプローチは何ですか?
TypeScriptの依存性注入に infuse.js を使用します。
/// <reference path="definition/infusejs/infusejs.d.ts"/>
this.injector = new infuse.Injector();
this.injector.mapClass( 'TodoController', TodoController );
this.injector.mapClass( 'TodoView', TodoView );
this.injector.mapClass( 'TodoModel', TodoModel, true ); // 'true' Map as singleton
export class TodoController
{
static inject = ['TodoView', 'TodoModel'];
constructor( todoView:TodoView, todoModel:TodoModel )
{
}
}
タイプベースではなく文字列ベースです(リフレクションはTypeScriptではまだ可能ではないため)。それにもかかわらず、それは私のアプリケーションで非常にうまく機能します。
私は、コンテキストバインディングなどの高度な依存関係注入機能を備えたInversifyJSと呼ばれるIoCコンテナーを開発しました。
それを使用するには、3つの基本的な手順に従う必要があります。
アノテーションAPIは、Angular 2.0に基づいています:
import { injectable, inject } from "inversify";
@injectable()
class Katana implements IKatana {
public hit() {
return "cut!";
}
}
@injectable()
class Shuriken implements IShuriken {
public throw() {
return "hit!";
}
}
@injectable()
class Ninja implements INinja {
private _katana: IKatana;
private _shuriken: IShuriken;
public constructor(
@inject("IKatana") katana: IKatana,
@inject("IShuriken") shuriken: IShuriken
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); };
public sneak() { return this._shuriken.throw(); };
}
バインディングAPIはNinjectに基づいています:
import { Kernel } from "inversify";
import { Ninja } from "./entities/ninja";
import { Katana } from "./entities/katana";
import { Shuriken} from "./entities/shuriken";
var kernel = new Kernel();
kernel.bind<INinja>("INinja").to(Ninja);
kernel.bind<IKatana>("IKatana").to(Katana);
kernel.bind<IShuriken>("IShuriken").to(Shuriken);
export default kernel;
解決APIはNinjectに基づいています:
import kernel = from "./inversify.config";
var ninja = kernel.get<INinja>("INinja");
expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true
最新リリース(2.0.0)は、多くのユースケースをサポートしています。
詳細は https://github.com/inversify/InversifyJS で確認できます。
これを試してください Dependency Injector(Typejector)
GitHub Typejector
新しいTypeScript 1.5では、アノテーション方法を使用できます
例えば
@injection
class SingletonClass {
public cat: string = "Kitty";
public dog: string = "Hot";
public say() {
alert(`${this.cat}-Cat and ${this.dog}-Dog`);
}
}
@injection
class SimpleClass {
public say(something: string) {
alert(`You said ${something}?`);
}
}
@resolve
class NeedInjectionsClass {
@inject(SingletonClass)
public helper: SingletonClass;
@inject(SimpleClass)
public simpleHelper: SimpleClass;
constructor() {
this.helper.say();
this.simpleHelper.say("wow");
}
}
class ChildClass extends NeedInjectionsClass {
}
var needInjection = new ChildClass();
質問の場合:次の例のように、一部のプロパティは疑似インターフェイス(または抽象クラス)を実現する必要があります。
class InterfaceClass {
public cat: string;
public dog: string;
public say() {
}
}
@injection(true, InterfaceClass)
class SingletonClass extends InterfaceClass {
public cat: string = "Kitty";
public dog: string = "Hot";
public say() {
alert(`${this.cat}-Cat and ${this.dog}-Dog`);
}
}
@injection(true, InterfaceClass)
class MockInterfaceClass extends InterfaceClass {
public cat: string = "Kitty";
public dog: string = "Hot";
public say() {
alert(`Mock-${this.cat}-Cat and Mock-${this.dog}-Dog`);
}
}
@injection
class SimpleClass {
public say(something: string) {
alert(`You said ${something}?`);
}
}
@resolve
class NeedInjectionsClass {
@inject(InterfaceClass)
public helper: InterfaceClass;
@inject(SimpleClass)
public simpleHelper: SimpleClass;
constructor() {
this.helper.say();
this.simpleHelper.say("wow");
}
}
class ChildClass extends NeedInjectionsClass {
}
var needInjection = new ChildClass();
注:モックインジェクションは、インターフェイスのクラスクリエーターを再定義するため、ソースコードの後に定義する必要があります
Angular2を使用する人のために、私はFluency Injection https://www.npmjs.com/package/fluency-injection を開発しました。ドキュメントは非常に完全であり、Angular2のDIの動作を模倣しています。
フィードバックは大歓迎です、それがあなたの役に立てば幸いです:)
これを試してみることができます: https://www.npmjs.com/package/easy-injectionjs 。これは、汎用的な依存関係注入パッケージです。
@EasySingletonは、アプリケーション全体で依存関係の単一インスタンスを作成します。ある種のサービスに最適です。
@EasyPrototypeは、依存関係のインスタンスを必要な数だけ作成します。変更可能な依存関係に最適です。
@EasyFactoryは主に継承に使用されます。
このパッケージを使用して何でもできます:簡単な使用法(readmeから):
import { Easy, EasyFactory, EasyPrototype, EasySingleton } from 'easy-injectionjs';
@EasyFactory()
abstract class Person {
abstract getName();
abstract setName(v: string);
}
// @EasyObservable()
@EasySingleton()
class Somebody extends Person{
// @Easy()
constructor (private name: string) {
super()
this.name = 'Sal';
}
public getName() {
return this.name;
}
public setName(v: string) {
this.name = v;
}
}
@EasyPrototype()
class Nobody extends Person{
@Easy()
somebody: Person;
constructor () {
super()
}
public getName() {
return this.somebody.getName();
}
public setName(v: string) {
this.somebody.setName(v);
}
}
@EasyPrototype()
class Data {
@Easy()
somebody: Person;
name: string;
change(v: string) {
this.somebody.setName(v);
}
getName(): string {
return this.somebody.getName();
}
}
let n = new Nobody();
console.log(n.getName()) // Prints Sal
n.setName('awesome');
console.log(n.getName()) // Prints awesome
let d = new Data()
console.log(d.getName()) // Prints awesome
d.change('Gelba')
console.log(n.getName()) // Prints Gelba
d.change('kaa')
console.log(n.getName()) // Prints Kaa
ノードモジュールを注入したい場合でも、これを行うことができます:
import * as IExpress from 'express';
import { Easy, EasySingleton } from 'easy-injectionjs';
@EasySingleton()
class Express extends IExpress {}
@EasySingleton()
export class App {
@Easy()
private _express: Express;
}
let app = new App();
console.log(app)
もちろん、高速サーバーの使用はコンソールのロギング用ではありません。これはテスト用です:D。
それが役に立てば幸い:D
TypeScriptは、requirejsなどのAMDローダーで適切に動作します。 TypeScriptが適切に構成されていれば、完全にAMD準拠のJavaScriptが出力されます。
テスト状況では、テスト可能なモジュールを挿入するようにrequirejsを構成できます。
あなたは解決策を使うことができます:
JavaScript/TypeScriptの軽量の依存性注入コンテナ
import {autoInjectable, container} from "tsyringe";
class MyService {
move(){
console.log('myService move 123', );
}
}
class MyServiceMock {
move(){
console.log('mock myService move 777', );
}
}
@autoInjectable()
export class ClassA {
constructor(public service?: MyService) {
}
move(){
this.service?.move();
}
}
container.register(MyService, {
useClass: MyServiceMock
});
new ClassA().move();
出力:
myService move 777のモック