javascript - 从 ngOnInit 调用的 Angular 2 单元测试函数

标签 javascript angular unit-testing

我正在尝试对组件内的函数进行单元测试,该函数是根据初始条件从 ngOnInit 调用的:

ngOnInit() {
    if (this.list.length === 0) {
        return this.loadData();
    }

    return this.isLoading = false;
}

// I'm calling here because it could also be called from button on the UI
loadData() {
    this.apiService.apiGet().subscribe((response) => {
        // handle data
        return this.isLoading = false;
    }, (error) => {
        // handle error
        return this.isLoading = false;
    })
}

但我无法测试它,除非我在测试时手动调用该函数。这是我的测试代码:

// THIS CODE WORKS
it('should be false after calling loadData()', async(() => {
    component.loadData();
    fixture.detectChanges();

    fixture.whenStable().then(() => {
        expect(component.isLoading).toBeFalsy();
    });
}));

// THIS CODE DOESN'T work
it('should be false after calling loadData()', async(() => {
    spyOn(component,'loadData').and.returnValue({code:'success'});
    fixture.detectChanges();

    fixture.whenStable().then(() => {
        expect(component.isLoading).toBeFalsy();
    });
}));

这也是我用来模拟 apiGet 函数的一段代码:

apiGet() {
    return Observable.of({ data: 'success' });
}

但是我知道 ngOnInit 正在执行并且函数正在被调用,因为这个测试通过了:

it('should be called if list array is empty', () => {
    spyOn(component,'loadData').and.returnValue({code:'success'});
    fixture.detectChanges();

    expect(component.loadData).toHaveBeenCalled();
});

我做错了什么?为什么测试失败没有达到最终的 promise ?

最佳答案

这个模拟方法没有设置 isLoading,但它返回一个与这里无关的值:

spyOn(component,'loadData').and.returnValue({code:'success'});

所以它的行为明显不同于真正的方法。如果这意味着这使得这个期望为假,那么就是这样:

expect(component.isLoading).toBeFalsy();

正确的测试方法是在几个独立的规范中逐行测试:

// ngOnInit test
spyOn(component, 'loadData');
this.list.length = 0;
fixture.detectChanges();
expect(component.loadData).toHaveBeenCalled();
expect(component.isLoading).toBe(true);

// ngOnInit test
spyOn(component, 'loadData');
this.list.length = 1;
fixture.detectChanges();
expect(component.loadData).not.toHaveBeenCalled();
expect(component.isLoading).toBe(false);

// loadData test
const apiServiceMock = {
  apiGet: jasmine.createSpy().and.returnValue(Observable.of(...))
};
this.apiService = apiServiceMock; // or mock via DI
spyOn(component, 'loadData').andCallThrough();
fixture.detectChanges();
// OR
// component.loadData()
expect(component.loadData).toHaveBeenCalled();
expect(apiServiceMock.apiGet).toHaveBeenCalled()
expect(component.isLoading).toBe(false);

// loadData test
const apiServiceMock = {
  apiGet: jasmine.createSpy().and.returnValue(Observable.throw(...))
};
// the rest is same

// loadData test
const apiServiceMock = {
  apiGet: jasmine.createSpy().and.returnValue(Observable.empty())
};
fixture.detectChanges();
expect(component.loadData).toHaveBeenCalled();
expect(apiServiceMock.apiGet).toHaveBeenCalled()
expect(component.isLoading).toBe(true);

关于javascript - 从 ngOnInit 调用的 Angular 2 单元测试函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44617366/

相关文章:

javascript - 在 Firefox OS 验证器中检测到 CSP 违规

javascript - 用于动态页面加载的 Bootstrap 预输入选择器

angular - 使用 Angular 在单元测试覆盖率中包含组件模板

node.js - 无法在 ionic 3 应用程序中的 ios 设备上存储 cookie

java - 如何从命令行(没有 Maven/Gradle)启动 JUnit 5(平台)?

javascript - 获取触发 focusout 事件的元素

javascript - 在javascript jquery中使用新行

node.js - 如何禁止用户在 Express/Electron 应用程序中通过常规浏览器查看应用程序

python - PyTest 警报/消息框

c# - 在单元测试中模拟类中的类