Typescript-Interface/Type-definition을 스터브하는 방법
저는 AngularJS 1.X 프로젝트에서 Typescript와 함께 일하고 있습니다.나는 다른 목적으로 다른 Javascript 라이브러리를 사용한다.소스를 유닛 테스트하기 위해 타이핑(= 인터페이스)을 사용하여 종속성을 스터브하려고 합니다.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
하고 있는 은, 는 가가지 the the, 가 use use use use use use use use use 를 사용하고 있는 것입니다.any
테스트 케이스에서 호출된 모든 메서드를 구현하거나 인터페이스를 구현하고 전체 인터페이스를 구현합니다.[ ] : ] : 。
각 메서드에 대해 구현이 비어 있고 입력된 개체를 생성하려면 어떻게 해야 합니까?나는 시논을 조롱의 목적으로 사용하고 있지만, 다른 도서관도 이용할 수 있다.
PS: Typescript에 의해 인터페이스가 지워지는 것은 알고 있습니다.그래도 해결하고 싶다:)
저는 qUnit과 Sinon을 사용하여 Typescript 테스트를 작성했고, 당신이 설명한 것과 똑같은 고통을 경험했습니다.
다음과 같은 인터페이스에 의존하고 있다고 가정합니다.
interface IDependency {
a(): void;
b(): boolean;
}
저는 sinon stub/spy와 주조물에 기반한 몇 가지 방법을 사용하여 추가 공구/라이브러리의 필요성을 가까스로 피했습니다.
빈 오브젝트 리터럴을 사용하여 코드에서 사용되는 함수에 sinon stub을 직접 할당합니다.
//Create empty literal as your IDependency (usually in the common "setup" method of the test file) let anotherDependencyStub = <IDependency>{}; //Set stubs for every method used in your code anotherDependencyStub.a = sandbox.stub(); //If not used, you won't need to define it here anotherDependencyStub.b = sandbox.stub().returns(true); //Specific behavior for the test //Exercise code and verify expectations dependencyStub.a(); ok(anotherDependencyStub.b()); sinon.assert.calledOnce(<SinonStub>anotherDependencyStub.b);
코드에 필요한 메서드의 빈 구현과 함께 오브젝트 리터럴을 사용한 후 필요에 따라 메서드를 sinon spy/stub로 랩합니다.
//Create dummy interface implementation with only the methods used in your code (usually in the common "setup" method of the test file) let dependencyStub = <IDependency>{ a: () => { }, //If not used, you won't need to define it here b: () => { return false; } }; //Set spies/stubs let bStub = sandbox.stub(dependencyStub, "b").returns(true); //Exercise code and verify expectations dependencyStub.a(); ok(dependencyStub.b()); sinon.assert.calledOnce(bStub);
qUnit 모듈에서 제공하는 것과 같은 sinon 샌드박스 및 공통 셋업/해체와 결합하면 매우 잘 작동합니다.
- 공통 설정에서 종속성에 대한 새 샌드박스와 모의 개체 리터럴을 생성합니다.
- 테스트에서는 spy/stub만 지정하면 됩니다.
다음과 같은 경우(첫 번째 옵션을 사용하지만 두 번째 옵션을 사용하는 경우에도 동일하게 작동합니다).
QUnit["module"]("fooModule", {
setup: () => {
sandbox = sinon.sandbox.create();
dependencyMock = <IDependency>{};
},
teardown: () => {
sandbox.restore();
}
});
test("My foo test", () => {
dependencyMock.b = sandbox.stub().returns(true);
var myCodeUnderTest = new Bar(dependencyMock);
var result = myCodeUnderTest.doSomething();
equal(result, 42, "Bar.doSomething returns 42 when IDependency.b returns true");
});
아직 이상적인 솔루션은 아니지만 상당히 잘 작동하고 추가 라이브러리가 필요하지 않으며 필요한 추가 코드의 양을 관리 가능한 수준으로 유지합니다.
최신 TypeMoq(버전 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");
간략한 답변은 Typescript에서는 컴파일 시간이나 런타임 "반영"을 제공하지 않기 때문에 가능하지 않다는 것입니다.모의 라이브러리는 인터페이스의 구성원을 반복할 수 없습니다.
스레드 참조:https://github.com/Microsoft/TypeScript/issues/1549
이는 의존관계를 조롱하는 것이 개발 워크플로우의 중심인 TDD 개발자들에게는 불행한 일입니다.
단, 다른 답변에서 설명한 바와 같이 메서드를 신속하게 스텁하기 위한 많은 기술이 있습니다.이 옵션들은 정신적인 적응을 조금 더 하면 효과가 있을 것이다.
편집: Typescript Abstract Syntax Tree(AST)는 컴파일 시간 "내부 검사"로, 아마도 mock을 생성하는 데 사용될 수 있습니다.하지만 실용적인 도서관을 만든 사람이 있는지 모르겠다.
송신원: npmjs:
Mocking interfaces You can mock interfaces too, just instead of passing type to mock function, set mock function generic type Mocking interfaces requires Proxy implementation let mockedFoo:Foo = mock<FooInterface>(); // instead of mock(FooInterface) const foo: SampleGeneric<FooInterface> = instance(mockedFoo);
ts-blockito는 버전 2.4.0 이후의 모의 인터페이스를 지원합니다.
할 수 은 거의 .TypeMoq
,TeddyMocks
★★★★★★★★★★★★★★★★★」Typescript-mockify
'아예'는 '아예 '아예'는 '아예'로 되어 있습니다.
github 저장소를 확인하고 원하는 저장소를 선택합니다.링크:
- TeddyMocks : https://github.com/mbraude/TeddyMocks
- TypeMoq : https://github.com/florinn/typemoq
- TypeScriptMockify : https://github.com/brechtbilliet/typescript-mockify
좀 더 도 있지만 시논 리브를 .<any>
<IDependency>
type (타입스크립트와 함께 Sinon을 사용하는 방법)
moq.ts를 시도할 수 있지만 프록시 개체에 따라 다릅니다.
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
Safe Mock은 꽤 좋지만, 안타깝게도 지금은 유지보수가 되지 않은 것 같습니다.완전히 공개하자면, 나는 작가와 함께 일했었다.
import SafeMock, {verify} from "safe-mock";
const mock = SafeMock.build<SomeService>();
// specify return values only when mocks are called with certain arguments like this
when(mock.someMethod(123, "some arg")).return("expectedReturn");
// specify thrown exceptions only when mocks are called with certain arguments like this
when(mock.someMethod(123, "some arg")).throw(new Error("BRR! Its cold!"));
// specify that the mock returns rejected promises with a rejected value with reject
when(mock.someMethod(123)).reject(new Error("BRR! Its cold!"));
//use verify.calledWith to check the exact arguments to a mocked method
verify(mock.someMethod).calledWith(123, "someArg");
SafeMock은 모크에서 잘못된 타입을 반환할 수 없습니다.
interface SomeService {
createSomething(): string;
}
const mock: Mock<SomeService> = SafeMock.build<SomeService>();
//Won't compile createSomething returns a string
when(mock.createSomething()).return(123);
이제 가능합니다.인터페이스 메타데이터를 런타임에 사용할 수 있도록 하는 향상된 버전의 타이프스크립트 컴파일러를 출시했습니다.예를 들어 다음과 같이 쓸 수 있습니다.
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
-----
이 모든 정보를 사용하여 필요에 따라 프로그래밍 방식으로 스터브를 구축할 수 있습니다.
제 프로젝트는 여기서 보실 수 있습니다.
언급URL : https://stackoverflow.com/questions/37027776/how-to-stub-a-typescript-interface-type-definition
'source' 카테고리의 다른 글
파일과 함께 로컬로 로드된 모바일 WebView에서 CORS cookie 자격 정보:// (0) | 2023.02.17 |
---|---|
JSON을 사용한 시리얼화된 필드의 순서.그물 (0) | 2023.02.17 |
올바른 URL을 전달하려면 어떻게 해야 합니까?추가 앰퍼 및 문제 없이 JQuery 메서드에 대한 조치? (0) | 2023.02.17 |
Grid Builder Visual Composer에서 변수의 게시 ID 가져오기 (0) | 2023.02.17 |
AngularJS 지시 전달 문자열 (0) | 2023.02.17 |