[英]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 Control
和Dependency Injection
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.