【问题标题】:Testing method inside a subscribe is called, when mocking an observable模拟可观察对象时,调用订阅内的测试方法
【发布时间】:2021-11-04 01:54:22
【问题描述】:

在我的测试“应该发出动作完成”中,我试图测试在调用“OnBookActionClick”方法时是否调用了“bookActionCompleted”的发出函数。这个 emit 函数在传递给我的服务方法返回的 void observable 的 subscribe 函数的方法中调用。

不幸的是,传递给组件订阅方法的代码永远不会通过运行我的测试来调用。在这些测试中,我通过返回 of() 来模拟“publishBook”和“unpublishBook”的响应,我怀疑这可能是问题的原因,但是我完全不知道如何继续。

组件

import { Component, EventEmitter, Input, Output } from '@angular/core';

import { Library, LibraryBook } from '../../models';
import { LibraryService } from '../../services';

@Component({
    selector: 'librarycatalogue-books-view',
    templateUrl: './books-view.component.html',
    styleUrls: ['./books-view.component.scss']
})
export class BooksViewComponent {
    @Input() library!: Library;
    @Output() bookActionCompleted = new EventEmitter();

    constructor(private libraryService: LibraryService) {}

    onBookActionClick(book: LibraryBook) {
        const action = book.isPublished
            ? this.libraryService.unpublishBook(this.library.libraryId, book.bookId)
            : this.libraryService.publishBook(this.library.libraryId, book.bookId);
        action.subscribe(() => {
            this.bookActionCompleted.emit()
        });
    }
}

服务方法(被模拟)

publishBook(libraryId: string, bookId: string): Observable<void> {
    return this.http.put<void>(`${this.baseUrl}/${libraryId}/book/${bookId}/publish`, null);
}

unpublishBook(libraryId: string, bookId: string): Observable<void> {
    return this.http.put<void>(`${this.baseUrl}/${libaryId}/book/${bookId}/unpublish`, null);
}

测试

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { createSpyObject, SpyObject } from '@ngneat/spectator/jest';
import { of } from 'rxjs';

import { Library, LibraryBook } from '../../models';
import { LibraryService } from '../../services';
import { BooksViewComponent } from './books-view.component';

describe('BooksViewComponent', () => {
  let component: BooksViewComponent;
  let fixture: ComponentFixture<BooksViewComponent>;
  let libraryService: SpyObject<LibraryService>;

  beforeEach(async () => {

    libraryService = createSpyObject(LibraryService);
    libraryService.publishBook.mockReturnValue(of());
    libraryService.unpublishBook.mockReturnValue(of());

    await TestBed.configureTestingModule({
      declarations: [ BooksViewComponent ],
      imports: [HttpClientTestingModule],
      providers: [
        { provide: LibraryService, useValue: libraryService }
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(BooksViewComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  describe('On book action click', () => {
    let library: Library;
    let publishedBook: LibraryBook;
    let unpublishedBook: LibraryBook;

    beforeEach(() => {
      library = {  libraryId: '1',
                name: 'New York Library',
                books: [
                { book: 1, bookId: '1', isPublished: false},
                { book: 2, bookId: '2', isPublished: true }
              ]
            };

            publishedBook = library.books.filter(x => x.isPublished)[0];
            unpublishedBook = library.books.filter(x => !x.isPublished)[0];

      component.library = library;
      jest.spyOn(component.bookActionCompleted, 'emit');
    });
    
    describe('If item is published', () => {
      it('should be unpublished', () => {
        component.onBookActionClick(publishedBook);

        expect(libraryService.unpublishBook).toHaveBeenCalled();
      })

      it('should emit action complete', () => {
        component.onBookActionClick(publishedBook);
        expect(component.bookActionCompleted.emit).toHaveBeenCalledTimes(1);
      })
    });

  });
});

【问题讨论】:

    标签: angular rxjs jestjs


    【解决方案1】:

    您可以订阅 bookActionCompleted EventEmitter 并在传递给 jest 函数的“done”函数参数的帮助下终止测试。

    it('should emit action complete', (done) => {
        // test will be green if done cb is called:
        component.bookActionCompleted.subscribe(done);
        component.onBookActionClick(publishedBook);
    })
    

    【讨论】:

      【解决方案2】:

      我只是偶然偶然发现了答案。将 mock 更改为 return of(undefined) 而不是 of() 已经触发了 emit 方法。

      不知道为什么会这样,很想知道是否有人有答案。

      之前(不工作)

      libraryService.publishBook.mockReturnValue(of());
      libraryService.unpublishBook.mockReturnValue(of());
      

      之后(工作)

      libraryService.publishBook.mockReturnValue(of(defined));
      libraryService.unpublishBook.mockReturnValue(of(defined));
      

      【讨论】:

        猜你喜欢
        • 2016-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-14
        • 2017-06-21
        • 1970-01-01
        • 1970-01-01
        • 2017-10-31
        相关资源
        最近更新 更多