运行 Angular/Jasmine/Karma,我有一个组件使用服务来设置 Observable“items”数组的值。我使用异步管道显示它。效果很好。
现在,我正在尝试设置一个单元测试并让它通过,但我不确定我是否正确地验证了“items”数组是否获得了正确的值。
这是相关的组件 .html 和 .ts :
export class ViperDashboardComponent implements OnInit, OnDestroy {
items: Observable<DashboardItem[]>;
constructor(private dashboardService: ViperDashboardService) { }
ngOnInit() {
this.items = this.dashboardService.getDashboardItems();
}
}
<ul class="list-group">
<li class="list-group-item" *ngFor="let item of items | async">
<h3>{{item.value}}</h3>
<p>{{item.detail}}</p>
</li>
</ul>
还有我的 component.spec.ts:
beforeEach(() => {
fixture = TestBed.createComponent(ViperDashboardComponent);
component = fixture.componentInstance;
viperDashboardService =
fixture.debugElement.injector.get(ViperDashboardService);
mockItems = [
{ key: 'item1', value: 'item 1', detail: 'This is item 1' },
{ key: 'item2', value: 'item 2', detail: 'This is item 2' },
{ key: 'item3', value: 'item 3', detail: 'This is item 3' }
];
spy = spyOn(viperDashboardService, 'getDashboardItems')
.and.returnValue(Observable.of<DashboardItem[]>(mockItems));
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should call getDashboardItems after component initialzed', () => {
fixture.detectChanges();
expect(spy.calls.any()).toBe(true, 'getDashboardItems should be called');
});
it('should show the dashboard after component initialized', () => {
fixture.detectChanges();
expect(component.items).toEqual(Observable.of(mockItems));
});
具体来说,我想知道:
1) 我开始创建一个异步“it”测试,但当它不起作用时我感到很惊讶。为什么在我处理异步数据流时同步测试有效?
2) 当我检查 component.items 与 Observable.of(mockItems) 的等价性时,我是否真的在测试这些值是否相等?还是我只是在测试它们都是 Observable?有没有更好的办法?
最佳答案
Angular 提供了用于测试异步值的实用程序。您可以使用 async
utility with the fixture.whenStable
方法或 fakeAsync
utility with the tick()
function .然后使用 DebugElement
,您实际上可以查询您的模板以确保正确加载值。
两种测试方法都有效。
将 async
实用程序与 whenStable
一起使用:
保持你的设置不变,你很高兴去那里。您需要添加一些代码来获取列表的调试元素。在您的 beforeEach
中:
const list = fixture.debugElement.query(By.css('list-group'));
然后您可以深入了解该列表并获取单个项目。我不会深入探讨如何使用 DebugElement
,因为这超出了这个问题的范围。在此处了解更多信息:https://angular.io/guide/testing#componentfixture-debugelement-and-querybycss .
然后在你的单元测试中:
it('should get the dashboard items when initialized', async(() => {
fixture.detectChanges();
fixture.whenStable().then(() => { // wait for your async data
fixture.detectChanges(); // refresh your fake template
/*
now here you can check the debug element for your list
and see that the items in that list correctly represent
your mock data
e.g. expect(listItem1Header.textContent).toEqual('list item 1');
*/
}
}));
将 fakeAsync
实用程序与 tick
结合使用:
it('should get the dashboard items when initialized', fakeAsync(() => {
fixture.detectChanges();
tick(); // wait for async data
fixture.detectChanges(); // refresh fake template
/*
now here you can check the debug element for your list
and see that the items in that list correctly represent
your mock data
e.g. expect(listItem1Header.textContent).toEqual('list item 1');
*/
}));
因此,总而言之,不要为了简化测试而从模板中删除 async
管道。 async
管道是一个很棒的实用程序,可以为您做很多清理工作,而且 Angular 团队为这个确切的用例提供了一些非常有用的测试实用程序。希望上述技术之一有效。听起来像是使用 DebugElement
并且上述实用程序之一会对您有很大帮助:)
关于angular - 从服务返回的 Observable 的单元测试值(使用异步管道),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48328292/