angular - 设置模拟服务并使用 jasmine/karma 和 Angular 调用它时出现问题
问题描述
我有一个调用另一个方法的方法。在该方法中,我订阅了一项服务,如果有匹配项,则使用 Angular 路由器服务进行导航。这是一个stackBlitz 示例
goToMain(): void {
this.viewFunc(this.queryString);
}
viewFunc(queryString): void {
this.reportService.getAnotherReport(queryString).subscribe(x => {
if (x.label.toLowerCase() === "accept & view") {
const url = "main";
this.router.navigate([url], {
queryParams: { queryString: queryString }
});
}
});
}
我成功地在我的规范文件中创建了一个测试来测试该viewFunc
方法是否被调用。然后,我尝试从下一个方法中调用的服务模拟订阅。我试图测试两件事 A. 订阅称为 B. 如果匹配则导航。
我收到错误“预期的间谍 getAnotherReport 已被调用。 ”
it("should call service", () => {
const queryString = "10987";
const testee = component;
expect(testee).toBeTruthy();
const routerSpy = { navigate: jasmine.createSpy("navigate") };
const mySpy = jasmine.createSpy("getAnotherReport").and.callThrough();
testee.viewFunc(queryString);
expect(mySpy).toHaveBeenCalled();
expect(routerSpy.navigate).toHaveBeenCalledWith(["/main"], {
queryParams: { queryString: queryString }
});
});
这是一个stackBlitz 示例
我还不太了解 jasmine 和单元测试,我怀疑我为我的规范文件设置了错误的描述/测试平台。因此,如果有人可以提供帮助并查看stackBlitz 示例,我将不胜感激。
解决方案
有几个错别字:
首先,我认为您的意思是声明getAnotherReport
为值,而不是类型:
let getAnotherReport = {
text: null,
ref: "7478B45D4D4F1400223BD2F1",
num: 19,
urn: "123",
title: "Test report",
label: "accept & view"
};
然后,在SearchComponent.viewFunc
你有url = 'main'
和你的规范中,你有:
expect(routerSpy.navigate).toHaveBeenCalledWith(["/main"], {
queryParams: { queryString: queryString }
});
它应该没有/
:
expect(routerSpy.navigate).toHaveBeenCalledWith(["main"], {
queryParams: { queryString: queryString }
});
现在,让我们看看有趣的事情。
我们将首先探索第一个断言:
const mySpy = jasmine.createSpy("getAnotherReport").and.callThrough();
/* ... */
testee.viewFunc(queryString);
/* .... */
expect(mySpy).toHaveBeenCalled();
这里的问题与您决定如何进行间谍活动有关viewFunc
。在这种情况下,您使用spyOn(component, "viewFunc");
了:这些是您调用时在后台发生的相关位spyOn
:
var originalMethod = obj[methodName],
spiedMethod = createSpy(methodName, originalMethod),
wherecreateSpy
将是一个空间谍,即它仅用于跟踪函数被调用了多少次,使用哪些参数等。但它不会使用原始实现,这不是你想要的,因为你也有断言关注ReportService
,它存在于viewFunc
的原始实现中。
为了使用初始实现,您可以使用.and.callThrough()
:
// a quick look at the fact that it uses the original function
SpyStrategy.prototype.callThrough = function() {
this.plan = this.originalFn;
return this.getSpy();
};
reportService = TestBed.get(ReportService);
// and here we are using it
spyOn(component, "viewFunc").and.callThrough();
把它们放在一起:
// you can get ahold of the current spy like this
const mySpy = mockReportService.getAnotherReport.and.returnValue(
of(getAnotherReport)
);
expect(testee).toBeTruthy();
testee.viewFunc(queryString);
expect(mySpy).toHaveBeenCalled();
现在进入第二个断言:
// inside providers array
{ provide: Router, useValue: routerSpy },
/* ... */
const routerSpy = { navigate: jasmine.createSpy("navigate") };
expect(routerSpy.navigate).toHaveBeenCalledWith(["main"], {
queryParams: { queryString: queryString }
});
在这种情况下,请注意您使用的对象与您模拟类的对象不同Router
。
您必须使用与模拟相关类相同的对象,因此解决此问题的方法是:
let routerSpy = { navigate: jasmine.createSpy("navigate") };
/* ... */
// inside providers array
{ provide: Router, useValue: routerSpy },
/* ... */
const mySpy = mockReportService.getAnotherReport.and.returnValue(
of(getAnotherReport)
);
expect(testee).toBeTruthy();
testee.viewFunc(queryString);
expect(mySpy).toHaveBeenCalled();
expect(routerSpy.navigate).toHaveBeenCalledWith(["main"], {
queryParams: { queryString: queryString }
});
小建议
我对 Jasmine 也不是很熟悉,但它帮助我了解了它在引擎盖下的作用。无需了解每一个微小细节,您至少可以直观地了解如何解决问题。因此,当在 StackBlitz 应用程序中时,例如您链接的应用程序,您可以:
- 打开开发工具
- 按下
CTRL + P
并输入jasmine.js
(可能有多个文件,正确的文件是其中包含已知方法的文件,例如callThrough
- 您可以通过按下CTRL + SHIFT + O
并输入方法名称来检查)
此外,您可以在那里搜索search.component.ts
并放置一些断点,以获得更流畅的调试体验。
推荐阅读
- apache-spark - 在用压缩文件替换 HDFS 中的小文件时,如何避免破坏活动的 Hive/Presto 查询?
- reactjs - 我如何使用蚂蚁设计在反应 js 中禁用小屏幕上的 1 个选项卡
- graph - 如何订阅整个枪图的变化?
- javascript - jquery过滤器搜索应该根据文本选择匹配的DIV
- java - 反应本机图像获取/上传
- angular - PrimeNG 表单验证
- sql - 需要帮助解决慢查询
- node.js - nodejs - 检测文件结尾(EOF)
- visual-studio - .net core visual studio publish 包括运行时
- r - 使用 dplyr 和 table 函数