如何在 Angular 中测试挂起的标志
How to test pending flag in Angular
我有 fetchBooks
从后端检索数据然后填充 books
变量的方法。
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
})
export class AppComponent implements OnInit {
isLoading: boolean;
books;
constructor(private booksService: BooksService) {}
ngOnInit() {
this.fetchBooks();
}
fetchBooks(): void {
this.isLoading = true;
this.booksService
.fetchBooks()
.subscribe(
response => {
this.isLoading = false;
this.books = response.data;
// ..
},
error => {
this.isLoading = false;
// ..
}
);
}
}
我需要为 isLoading
标志编写单元测试。我写了这样的东西
it('should work', async () => {
sut.fetchBooks();
// ...
expect(sut.isLoading).toBe(true);
// ...
expect(sut.isLoading).toBe(false);
});
但我与其他人斗争。也许有人知道如何解决它或知道一些解释它的文章?
我会这样做:
import { of } from 'rxjs';
....
it('should turn loading on when fetchBooks is called', () => {
// notice we don't resolve bookService.fetchBooks in this case so
// it doesn't go in the subscribe callback
sut.fetchBooks();
expect(sut.isLoading).toBe(true);
});
it('should turn loading off when bookService.fetchBooks resolves', () => {
// make bookService.fetchBooks return instantaneously this time.
spyOn(bookService, 'fetchBooks').and.returnValue(of({ data: [] }));
sut.fetchBooks();
expect(sut.isLoading).toBe(true);
expect(sut.books).toEqual([]); // use toEqual here because toBe uses triple equality
// and [] === [] returns false because it is comparing
// locations in memory
});
编辑
我将测试分成两部分以便测试更容易。
第一个测试 observable (bookService.fetchBooks) 没有 return observable 所以 this.isLoading = false
没有被遍历但是函数的开头如此 this.isLoading = true
.所以基本上这是测试函数的前半部分是好的,本质上 this.isLoading = true
发生在可观察的“解析”或发出之前。
第二个测试使用 .returnValue(of({ data: [] }));
立即解析 observable,因此我们测试当 observable 发出时加载被关闭。
我的解决方案是利用Subject来控制值的发射。将 subject.asObservable()
传递给您的 SUT 订阅的间谍。
import { Subject } from 'rxjs';
it('should correctly work', () => {
// replace SomeType with the type returned by booksService.fetchData()
const subject = new Subject<SomeType>();
spyOn(booksService, 'fetchData').and.returnValue(subject.asObservable());
const mockData: SomeType = {}; // put some data here, same type;
// bonus, you may want to check also that isLoading is initially false
// expect(sut.isLoading).toBe(false);
// check: after triggered, isLoading should be true until the subscription returns a value
sut.ngOnOnit();
expect(sut.isLoading).toBe(true);
// check: after the subscription receives a value, isLoading should be false
subject.next(mockData);
expect(sut.isLoading).toBe(false);
// bonus
expect(sut.data).toEqual(mockData);
expect(booksService.fetchData).toHaveBeenCalledTimes(1);
});
我有 fetchBooks
从后端检索数据然后填充 books
变量的方法。
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
})
export class AppComponent implements OnInit {
isLoading: boolean;
books;
constructor(private booksService: BooksService) {}
ngOnInit() {
this.fetchBooks();
}
fetchBooks(): void {
this.isLoading = true;
this.booksService
.fetchBooks()
.subscribe(
response => {
this.isLoading = false;
this.books = response.data;
// ..
},
error => {
this.isLoading = false;
// ..
}
);
}
}
我需要为 isLoading
标志编写单元测试。我写了这样的东西
it('should work', async () => {
sut.fetchBooks();
// ...
expect(sut.isLoading).toBe(true);
// ...
expect(sut.isLoading).toBe(false);
});
但我与其他人斗争。也许有人知道如何解决它或知道一些解释它的文章?
我会这样做:
import { of } from 'rxjs';
....
it('should turn loading on when fetchBooks is called', () => {
// notice we don't resolve bookService.fetchBooks in this case so
// it doesn't go in the subscribe callback
sut.fetchBooks();
expect(sut.isLoading).toBe(true);
});
it('should turn loading off when bookService.fetchBooks resolves', () => {
// make bookService.fetchBooks return instantaneously this time.
spyOn(bookService, 'fetchBooks').and.returnValue(of({ data: [] }));
sut.fetchBooks();
expect(sut.isLoading).toBe(true);
expect(sut.books).toEqual([]); // use toEqual here because toBe uses triple equality
// and [] === [] returns false because it is comparing
// locations in memory
});
编辑
我将测试分成两部分以便测试更容易。
第一个测试 observable (bookService.fetchBooks) 没有 return observable 所以 this.isLoading = false
没有被遍历但是函数的开头如此 this.isLoading = true
.所以基本上这是测试函数的前半部分是好的,本质上 this.isLoading = true
发生在可观察的“解析”或发出之前。
第二个测试使用 .returnValue(of({ data: [] }));
立即解析 observable,因此我们测试当 observable 发出时加载被关闭。
我的解决方案是利用Subject来控制值的发射。将 subject.asObservable()
传递给您的 SUT 订阅的间谍。
import { Subject } from 'rxjs';
it('should correctly work', () => {
// replace SomeType with the type returned by booksService.fetchData()
const subject = new Subject<SomeType>();
spyOn(booksService, 'fetchData').and.returnValue(subject.asObservable());
const mockData: SomeType = {}; // put some data here, same type;
// bonus, you may want to check also that isLoading is initially false
// expect(sut.isLoading).toBe(false);
// check: after triggered, isLoading should be true until the subscription returns a value
sut.ngOnOnit();
expect(sut.isLoading).toBe(true);
// check: after the subscription receives a value, isLoading should be false
subject.next(mockData);
expect(sut.isLoading).toBe(false);
// bonus
expect(sut.data).toEqual(mockData);
expect(booksService.fetchData).toHaveBeenCalledTimes(1);
});