如何存根 Typescript 接口/类型定义?

2024-01-12

我在 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

我现在的痛苦是我要么使用any并实现在我的测试用例中调用的所有方法,或者我实现接口并实现完整的接口。这是太多无用的代码:(。

如何生成每个方法都有空实现并且类型化的对象?我使用 Sinon 来进行模拟,但我也愿意使用其他库。

PS:我知道 Typescript 会删除接口...但我仍然想解决这个问题:)。


我一直在使用 qUnit 和 Sinon 编写 Typescript 测试,并且我经历了与您所描述的完全相同的痛苦。

假设您依赖于如下接口:

interface IDependency {
    a(): void;
    b(): boolean;
}

我通过使用几种基于 sinon 存根/间谍和铸造的方法,设法避免了对额外工具/库的需要。

  • 使用空对象字面量,然后直接将 sinon 存根分配给代码中使用的函数:

    //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 spies/stubs 中

    //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);
    

当您将它们与 sinon 沙箱和常见的安装/拆卸(如 qUnit 模块提供的)结合起来时,它们的工作效果非常好。

  • 在通用设置中,您为依赖项创建一个新的沙箱和模拟对象文字。
  • 在测试中,您只需指定间谍/存根。

像这样的东西(使用第一个选项,但如果使用第二个选项,也会以同样的方式工作):

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

我同意这仍然不是理想的解决方案,但它工作得相当好,不需要额外的库,并将所需的额外代码量保持在较低的可管理水平。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何存根 Typescript 接口/类型定义? 的相关文章

随机推荐