角度单元测试:数据服务中未更新的可观察变量值



我有一个组件使用的数据服务。

例如:

图书服务:

...
private book: Book;
private bookSubject = new BehaviorSubject<Book>(this.book);
bookChanged = this.bookSubject.asObservable();
...

书籍组件:

...
book: Book;
ngOnInit() {
this.bookService.bookChanged.subscribe(
(book: Book) => this.book = book;
)
}
...

组件的规范(测试文件(:

describe('BookComponent', () => {
let component: BookComponent;
let fixture: ComponentFixture<BookComponent>;
let bookServiceStub: Partial<BookService>;
bookServiceStub = {
bookChanged: of({id: 123, name: 'Book 1'})
};
beforeEach(async(() => {
TestBed
.configureTestingModule({
declarations: [BookComponent],
providers: [
{provide: BookService, useValue: bookServiceStub},
...
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BookComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should change the book with a new one', fakeAsync(() => {
const newBook = {
id: 769,
name: 'Book 2'
};
bookServiceStub.bookChanged = of(newBook);
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(component.book.id).toBe(newBook.id); // FAILS (still has old value)
expect(component.book).toBe(newBook); // FAILS (still has old value)
});
}));
});

因此,测试失败,因为"book"变量不会使用新值进行更新。

我在这里做错了什么?

注意:我实际上想测试组件中的订阅是否按预期工作!

原因:我想签入进一步的测试,当服务中的值更新时,DOM 是否自动更改

以下是发生的顺序:

beforeEach(() => {
fixture = TestBed.createComponent(BookComponent);
// The component is created now. So, its constructor is run and services instantiated.
// Also, ngOnInit is executed.
// ...
it('should change the book with a new one', fakeAsync(() => {
const newBook = {
id: 769,
name: 'Book 2'
};
// And now you're overwriting bookServiceStub's bookChanged property.
// The problem is, the component doesn't care at this point, it already has a subscription,
// and it's attached to the original bookChanged stream.
bookServiceStub.bookChanged = of(newBook);

如果在此套件中没有要运行的更多测试(或者不需要其中不同的bookChanged内容(,则只需在创建组件之前提前移动bookServiceStub.bookChanged = of(newBook)即可。

我自己花了一段时间才弄清楚 fixture.detectChanges((; 实际上正在启动组件的数据绑定。下面应该仍然有效,通过删除 fixture.detectChanges((;从 beforeEach(( 并将其放入每个测试中,您正在等待启动对组件的任何数据绑定。

beforeEach(() => {
fixture = TestBed.createComponent(BookComponent);
component = fixture.componentInstance;
});
it('should create', () => {
fixture.detectChanges();
expect(component).toBeTruthy();
});
it('should change the book with a new one', fakeAsync(() => {
const newBook = {
id: 769,
name: 'Book 2'
};
bookServiceStub.bookChanged = of(newBook);
fixture.detectChanges();
expect(component.book.id).toBe(newBook.id);
expect(component.book).toBe(newBook);
}));

添加component.ngOnInit();使我的测试成功运行。

it('should change the book with a new one', fakeAsync(() => {
const newBook = {
id: 769,
name: 'Book 2'
};
bookServiceStub.bookChanged = of(newBook);
component.ngOnInit(); // ADDED HERE
fixture.detectChanges();
expect(component.book.id).toBe(newBook.id);
expect(component.book).toBe(newBook);
}));

不过,这是一个好的做法吗? 还是我应该创建一个间谍等?

最新更新