【问题标题】:Unit test Angular 2 service subject单元测试 Angular 2 服务主题
【发布时间】:2017-12-20 01:24:08
【问题描述】:

我正在尝试为具有 Subject 属性和调用 .next() 的方法的 Angular 服务编写测试。

服务如下:

@Injectable()
export class SubjectService {
  serviceSubjectProperty$: Subject<any> = new Subject();

  callNextOnSubject(data: any) {
    this.serviceSubjectProperty$.next(data);
  }
}

以及该服务的测试文件:

import { TestBed, inject } from '@angular/core/testing';

import { SubjectService } from './subject.service';

describe('SubjectService', () => {

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        SubjectService
      ]
    });
  });

  it('callNextOnSubject() should emit data to serviceSubjectProperty$ Subject',
    inject([SubjectService], (subjectService) => {
      subjectService.callNextOnSubject('test');

      subjectServiceProperty$.subscribe((message) => {
        expect(message).toBe('test');
      })
  }));
});

如果我将 subjectService.callNextOnSubject 的参数从 'test' 更改为其他任何值,测试总是通过事件。

我也试过用async和fakeAsync包装所有东西,但结果是一样的。

测试callNextOnSubject 是否向serviceSubjectProperty$ 主题发送数据的正确方法是什么?

【问题讨论】:

  • 您应该在调用方法之前订阅,该主题没有任何重播/缓冲行为。
  • @jonrsharpe 成功了,谢谢。
  • 当您对服务进行单元测试时,您不应该使用角度测试基础架构。它所做的只是让你的测试代码更长,更容易出错。
  • @crdevdeu 如果其中一个答案是正确的 - 请标记它;)

标签: angular testing jasmine rxjs subject


【解决方案1】:

subscribe必须在之前,然后调用方法

it(`#${YourCompoent.prototype.yourMethod.name} subscribe must come before, and then call method`, fakeAsync( () => {
    yourServiceSubject.filter$.subscribe(ev => {
      expect(ev).toEqual(mock.mockFilterDefault())
    });
    component.sendFilterForm();
  }));

【讨论】:

    【解决方案2】:

    到目前为止,使用 jasmine 'done' 回调就可以解决问题,请查看以下文档: https://jasmine.github.io/api/edge/global(见 implementationCallback(doneopt))

    下面是一个使用你的测试用例的例子:

    it('callNextOnSubject() should emit data to serviceSubjectProperty$ Subject', (done) => {
        inject([SubjectService], (subjectService) => {
          subjectService.callNextOnSubject('test');
    
          subjectServiceProperty$.subscribe((message) => {
            expect(message).toBe('test');
            done();
          })
      }) // function returned by 'inject' has to be invoked
    });
    

    【讨论】:

    • 嘿@mth khaled,很好的解释,但是,我得到一个 TypeError: Cannot read property 'subscribe' of undefined fit('callNextOn_page() should emit page data', (done) =&gt; { inject([searchOrderSpy], (_page) =&gt; { searchOrderSpy._page(5) }) searchOrderSpy._page.subscribe((page) =&gt; { expect(page).toBe(5); done(); }) }),下面是服务中的实现changePage(newPage: number) { this._page.next(newPage); }
    【解决方案3】:

    我在寻找解决方案时发现了这篇文章:

    http://www.syntaxsuccess.com/viewarticle/unit-testing-eventemitter-in-angular-2.0

    它对我来说很好用(它很短,不要害怕打开它)。

    我把它贴在这里,也许它会帮助那些来到这个网站寻找答案的人。


    关于提出的问题 - 我认为你需要改变:

      subjectService.callNextOnSubject('test');
    
      subjectServiceProperty$.subscribe((message) => {
        expect(message).toBe('test');
      })
    

    到

      subjectServiceProperty$.subscribe((message) => {
        expect(message).toBe('test');
      })
    
      subjectService.callNextOnSubject('test');
    

    ,所以先订阅,然后发出事件。

    如果您在订阅之前发出'test',那么什么都不会“捕获”该事件。

    【讨论】:

      【解决方案4】:

      您应该测试调用主题后组件中更改的数据。应该只测试公共变量,而不是私有或受保护的; 例如:

      服务:

      @Injectable()
      export class SomeService {
          onSomeSubject: Subject<any> = new Subject();
      
          someSubject(string: string) {
              this.onSomeSubject.next(string);
          }
      }
      

      组件:

      export class SomeComponent {
          @Input() string: string;
      
          constructor(private service: SomeService) {
              service.onSomeSubject.subscribe((string: string) => {
                  this.string = string;
              }); //don't forget to add unsubscribe.
          }
      }
      

      测试:

      ...
      describe('SomeService', () => {
          let someService: SomeService; // import SomeService on top
          let someComponent: SomeComponent; // import SomeService on top
      
          beforeEach(() => {
              TestBed.configureTestingModule({
                  providers: [SomeService, SomeComponent]
              });
              injector = getTestBed();
              someService = injector.get(SomeService);
              someComponent = injector.get(SomeComponent);
          });
      
          describe('someSubject', () => {
              const string = 'someString';
      
              it('should change string in component', () => {
                  someService.someSubject(string);
                  expect(someComponent.string).tobe(string);
              });
          });
      });
      

      【讨论】:

        猜你喜欢
        • 2017-06-03
        • 1970-01-01
        • 2019-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-27
        • 1970-01-01
        相关资源
        最近更新 更多