javascript 타입 Typescript-Interface/Type 정의를 스텁하는 법?




타입 스크립트 constructor (5)

저는 AngularJS 1.X 프로젝트에서 Typescript를 사용합니다. 다른 목적으로 다른 자바 스크립트 라이브러리를 사용합니다. 내 소스를 단위 테스트하려면 입력 (= 인터페이스)을 사용하여 일부 종속성을 스터핑하고 싶습니다. 나는 ANY 형을 사용하고 싶지 않고 각 인터페이스 메소드에 대해 빈 메소드를 작성하지도 않는다.

나는 그런 식으로 할 수있는 방법을 찾고있다.

let dependency = stub(IDependency);
stub(dependency.b(), () => {console.log("Hello World")});
dependency.a(); // --> Compile, do nothing, no exception
dependency.b(); // --> Compile, print "Hello World", no exception

지금 당장 가지고있는 고통은 테스트 케이스에서 호출 된 모든 메소드를 구현하고 구현하거나 인터페이스를 구현하고 전체 인터페이스를 구현한다는 것입니다. 너무 쓸모없는 코드입니다. (.

각 메소드에 대해 빈 구현이 있고 유형이 지정된 객체를 생성하려면 어떻게해야합니까? 나는 조롱 목적으로 시논 (Sinon)을 사용하지만 다른 라이브러리도 사용하기 위해 열어 둡니다.

추신 : 저는 Typescript가 인터페이스를 지우고 있다는 것을 알고 있습니다 ...하지만 여전히 해결하고 싶습니다 :).


당신은 moq.ts 를 시도 할 수 있지만 Proxy 객체에 의존한다.

interface IDependency {
  a(): number;
  b(): string;
}


import {Mock, It, Times} from 'moq.ts';

const mock = new Mock<IDependency>()
  .setup(instance => instance.a())
  .returns(1);

mock.object().a(); //returns 1

mock.verify(instance => instance.a());//pass
mock.verify(instance => instance.b());//fail

이제는 가능합니다 . 런타임시 인터페이스 메타 데이터를 사용할 수있게 해주는 typescript 컴파일러의 향상된 버전을 릴리스했습니다. 예를 들어 다음과 같이 작성할 수 있습니다.

interface Something {

}

interface SomethingElse {
    id: number;
}

interface MyService {
    simpleMethod(): void;
    doSomething(p1: number): string;
    doSomethingElse<T extends SomethingElse>(p1: Something): T;
}

function printMethods(interf: Interface) {
    let fields = interf.members.filter(m => m.type.kind === 'function'); //exclude methods.
    for(let field of fields) {
        let method = <FunctionType>field.type;
        console.log(`Method name: ${method.name}`);
        for(let signature of method.signatures) {
            //you can go really deeper here, see the api: reflection.d.ts
            console.log(`\tSignature parameters: ${signature.parameters.length} - return type kind: ${signature.returns.kind}`);
            if(signature.typeParameters) {
                for(let typeParam of signature.typeParameters) {
                    console.log(`\tSignature type param: ${typeParam.name}`); //you can get constraints with typeParam.constraints
                }
            }
            console.log('\t-----')
        }
    }
}

printMethods(MyService); //now can be used as a literal!!

이것은 출력입니다.

$ node main.js
Method name: simpleMethod
        Signature parameters: 0 - return type kind: void
        -----
Method name: doSomething
        Signature parameters: 1 - return type kind: string
        -----
Method name: doSomethingElse
        Signature parameters: 1 - return type kind: parameter
        Signature type param: T
        -----

이러한 모든 정보를 사용하여 원하는 방식으로 스텁을 프로그래밍 방식으로 작성할 수 있습니다.

내 프로젝트를 here 찾을 수 있습니다.


짧은 대답은이 언어가 컴파일 타임이나 런타임 "리플렉션"을 제공하지 않기 때문에 Typescript에서는 불가능하다는 것 입니다. 모의 라이브러리가 인터페이스의 멤버를 반복하는 것은 불가능합니다.

스레드 참조 : https://github.com/Microsoft/TypeScript/issues/1549

의존성을 조롱하는 것이 개발 워크 플로우의 핵심 부분 인 TDD 개발자에게는 불행한 일입니다.

그러나 다른 답변에 설명 된 것처럼 메서드를 신속하게 스텁링하는 데는 여러 가지 기술이 있습니다. 이러한 옵션은 조금 정신적으로 조정하여 작업을 수행 할 수 있습니다.


TypeMoq , TeddyMocksTypescript-mockify 를 수행 할 수있는 라이브러리는 거의 없다.

github 리포지토리를 확인하고 더 좋아하는 링크를 선택하십시오. 링크 :

Sinon과 같은 더 많이 사용하는 라이브러리를 사용할 수도 있지만 먼저 <any> 유형을 사용하고 <IDependency> 유형으로 범위를 좁혀 야합니다 ( Sinon을 Typescript와 함께 사용하려면 어떻게해야합니까? ).


최신 TypeMoq (ver 1.0.2)는 런타임 (nodejs / browser)이 ES6에서 도입 된 Proxy 전역 객체를 지원하는 한 TypeScript 인터페이스 조롱을 지원합니다.

따라서, IDependency 다음과 같이 가정합니다.

interface IDependency {
    a(): number;
    b(): string;
}

TypeMoq로 조롱하면 다음과 같이 간단합니다.

import * as TypeMoq from "typemoq";
...
let mock = TypeMoq.Mock.ofType<IDependency>();

mock.setup(x => x.b()).returns(() => "Hello World");

expect(mock.object.a()).to.eq(undefined);
expect(mock.object.b()).to.eq("Hello World");




stubbing