繁体   English   中英

如何存根返回 promise 的 function?

[英]How to stub function that returns a promise?

我正在尝试使用 sinon 对 function 进行存根。 function 具有以下签名

export function getIndexDocument(
    svc: MetaHTTPService | ServiceConfig
): MetaPromise<RepoResponseResult<IndexDocument>> {

这是正确的方法吗

sandbox.stub(getIndexDocument).resolves({} as RepoResponseResult)

我试过了,但它返回一个错误。

这是 function 的调用方式。

我有一个名为 AssetsController 的 class 具有以下功能

 public async exploreIndexDocument(): Promise<Asset | undefined> {      
    // it makes an HTTP request and returns a promise that resolves with the following info { repoId: "", assetId: "" }

     const {
            result: { assignedDirectories }
     } = await getIndexDocument(this.serviceConfig).catch(err => {
        throw new Error(`Bad repsonse`);
     });

     return {
        repoId: result.repoId;
        assetId: result.assetId
     }

}

public async function copyAsset(asset) {
   const res = await this.exploreIndexDocument();
   const repoId = res.repoId;
   return asset.copy(repoId);
}

我正在尝试测试 function copyAsset,但它调用了调用 getIndexDocument 的 exploreIndexDocument。 getIndexDocument 在文件顶部导入并位于模块@ma/http 中。 getIndexDocument 发出 HTTP 请求。

鉴于它调用 getIndexDocument 发出 HTTP 请求,我该如何测试它?

根据文档,您不能存根现有的 function。

你可以:

// Create an anonymous sstub function
var stub = sinon.stub();

// Replaces object.method with a stub function. An exception is thrown
// if the property is not already a function.
var stub = sinon.stub(object, "method");

// Stubs all the object’s methods.
var stub = sinon.stub(obj);

你不能做的是只存根 function 像:

var stub = sinon.stub(myFunctionHere);

这是有道理的,因为如果您所拥有的只是对 function 的引用,那么您可以创建一个新的 function 来代替使用,然后将其传递到您的测试需要它的任何地方 Z34D1F91FB2E514B8576ZFABA17


我想你只是想要:

const myStub = sandbox.stub().resolves({} as RepoResponseResult)

在您的更新中,听起来您想将存根放在AssetsController class 上。 有关详细信息, 请参阅此答案,但在这种情况下,我认为您想要:

const myStub = sandbox
  .stub(AssetsController.prototype, 'exploreIndexDocument')
  .resolves({} as RepoResponseResult)

现在, AssetsController的实例调用其exploreIndexDocument方法,就应该使用存根。

操场

我认为你的大部分问题都可以通过重新审视你的架构来解决。 例如,无需在AssetController class 中创建对getIndexDocument的显式依赖,您只需将其注入即可。这将允许您根据上下文交换实现。

type IndexDocumentProvider = (svc: MetaHTTPService | ServiceConfig) => MetaPromise<RepoResponseResult<IndexDocument>>;

interface AssetControllerOptions {
  indexDocumentProvider: IndexDocumentProvider
}

class AssetController {
  private _getIndexDocument: IndexDocumentProvider;

  public constructor(options: AssetControllerOptions) {
    this._getIndexDocument = options.indexDocumentProvider;
  }
}

然后,您可以在任何地方使用this._getIndexDocument ,而不必担心如何使原始实现在测试中表现得像您想要的那样。 您可以简单地提供一个执行您想要的任何操作的实现。

describe('copyAsset', () => {
  it('fails on index document error.', () => {
    const controller = new AssetController({
      indexDocumentProvider: () => Promise.reject(new Error(':('));
    });
    ....
  });

  it('copies asset using repo id.', () => {
    const controller = new AssetController({
      indexDocumentProvider: () => Promise.resolve({ repoId: "420" })
    });
    ...
  });
});

如果你需要一些花哨的东西,你显然可以使用stubs而不是函数或任何东西。

上面我们删除了对实现的显式依赖,取而代之的是必须提供给 controller 的合同。 通常称为Inversion of ControlDependency Injection

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM