angular - 从服务返回的 Observable 的单元测试值(使用异步管道)

标签 angular unit-testing typescript jasmine karma-runner

运行 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/

相关文章:

javascript - 从重复嵌套的 JSON 中获取多个值

html - ( Angular )图像不会显示

angular - Angular 2 中的导入是如何工作的?

c# - 从您打算测试的类继承是否总是次优的?

javascript - 为 'cannot redeclare block-scoped variable' 变量获取 'message'

javascript - 如何在 Angular 中添加动态外部脚本?

node.js - Angular 2 SimpleChanges 对象在第一次 npm 启动时抛出错误

angular - 在 IIS 的虚拟目录下运行 Angular

c# - 如何让 nunit-console 在\bin\Debug\而不是\bin\x86\Debug 中查找程序集?

javascript - 如何测试包裹在另一个连接组件中的连接组件?