What’s Fixture?
先解释一下fixture
这个单词,它的意思是固定设施,比如室内的浴缸或抽水马桶。当然这里指的是测试中的固定设施,也就是我们要测试的组件。在Angular中,我们可以通过TestBed
来创建一个组件的fixture
,然后对这个fixture
进行测试。
通常来说,fixture
都是在beforeEach
中创建。
1 | describe('ProductComponent', () => { |
fixture.detectChanges()
fixture.detectChanges()
是用来触发组件的变更检测的,也就是说,当我们对组件的状态进行了修改之后,我们需要调用fixture.detectChanges()
来通知Angular进行变更检测,以便更新视图。
如果你的测试中包含对UI的检测,那么你就需要调用fixture.detectChanges()
。否则不需要。
来,举个例子!
We have a product component which just display the product name as ‘Computer’, and when user click the Change product name
button, we’ll update the product name to ‘Phone’.
1 | import { Component } from '@angular/core'; |
1 | <p id="product-name">Product name: {{name}}</p> |
Does this test case work?
1 | it('should have name as Computer', () => { |
Yes, it works, but, we don’t need to call fixture.detectChanges()
here, because we are testing the component’s property name
change directly, not the UI changes.
Does the following test case work?
1 | it('should change name', () => { |
No, it doesn’t work, because, you call component.changeName()
to change the product name, but you didn’t call fixture.detectChanges()
to trigger the change detection and update the view. so the product name on page is still ‘Computer’.
We can call fixture.detectChanges()
after component.changeName()
to fix this issue.
1 | it('should change name', () => { |
fixture.whenStable()
fixture.whenStable()
是用来等待异步任务完成的,为了使用这个函数,我们给product component添加一个异步任务,比如通过setTimeout
来模拟一个异步任务。
1 | getData() { |
1 | <button (click)="updateName()">Update name</button> |
接下来,我们测试一下updateName
方法。下面这个test case,没有调用fixture.detectChanges()
,但是仍然可以通过测试,为什么呢?
1 | it('should update name', async () => { |
其实,这个test case是有问题的,它根本没有通过测试,虽然我们使用async
标记了测试方法,但是async
要配合await
使用,而不是then
,实际上,这里的then
根本没有执行!
为了修复这个test case,我们可以将async
删除。(这里有待验证!!!)
1 | it('should update name', async () => { |
其实,这里根本就不需要fixture.whenStable()
,因为我们使用了await
,它会等待异步任务完成,所以我们可以直接这样写:
1 | it('should update name', async () => { |
那到底什么时候需要使用fixture.whenStable()
呢?当你测试的方法里面包含异步操作,但是这个方法又不返回Promise的时候,你就需要使用fixture.whenStable()
来等待异步任务完成。
思考题:
下面的代码能通过测试吗?
1 | it('should update name', () => { |
答案是:能!因为fixture.whenStable()
里面的代码根本就没有执行,如何修复?
1 | it('should update name', async () => { |
还可以在fixture.whenStable()
前面加上return
,因为Jest中如果返回一个Promise,Jest会等待这个Promise执行完成。详情看这里
1 | it('should update name', async () => { |
Conclusion
fixture.detectChanges()
- This function will trigger change detection.
- Change detection will updates the view.
- If you test UI changes, you need to call
fixture.detectChanges()
.
fixture.whenStable()
- This function will wait for the asynchronous tasks to complete.
- You should use this function in
async
function.