我如何对这个处理可观察对象的函数进行单元测试

分享于2023年05月08日 angular-test angular6 rxjs 问答
【问题标题】:how do I unit test this function which handles observables我如何对这个处理可观察对象的函数进行单元测试
【发布时间】:2023-05-07 06:12:01
【问题描述】:

我创建了这个函数,因为对于我的应用程序使用 http.post 发出的所有请求,这就是不同部分处理响应的方式。因此,我想创建一个函数,而不是复制代码。但我无法弄清楚如何对这个函数进行单元测试。

private editAnswerSubject: Subject;
subscribeToReturnedObservable(observable:Observable, subject:Subject) {
    observable.subscribe((res) => {
        const ev = >(res);
        if (ev.type === HttpEventType.Response) {
          const isResponseStructureOK: boolean = this.helper.validateServerResponseStructure(ev.body);
          if (isResponseStructureOK) {
            const response: ServerResponseAPI = ev.body;
            subject.next(new Result(response.result, response['additional-info']));

          } else {
            subject.next(new Result(messages.error, messages.invalidStructureOfResponse));
          }
        }
      },
      (error: ServerResponseAPI) => {
        const errorMessage: string = this.helper.userFriendlyErrorMessage(error);
        subject.next(new Result(messages.error, errorMessage));    
      },
      () => { // observable complete
      });
  }

  editAnswer(answer: Answer): any {
    const observable = this.bs.editAnswer(answer)
    this.subscribeToReturnedObservable(observable,this.editAnswerSubject);
  }

到目前为止我写的测试是

  describe('subscribeToReturnedObservable tests:', () => {
    beforeEach(() => {
      TestBed.configureTestingModule({
        imports: [HttpClientTestingModule],
        providers: [QuestionManagementService, HelperService, WebToBackendInterfaceService, AuthService, HttpClient, HttpHandler]
      });
    });

fit('should call send next value for the subject is the response from the server is ok', () => {
  const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
  const body = {"result":"success", "additional-info":"some additional info"};
  const receivedHttpEvent = new HttpResponse({body:body});
  let observable = new Observable();
  spyOn(observable,'subscribe').and.returnValue(receivedHttpEvent);
  spyOn(questionService['editQuestionSubject'],'next');
  questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
  observable.subscribe();
  expect(questionService['editQuestionSubject'].next).toHaveBeenCalled();
});
});

但它得到错误 Expected spy next to have been called.

  • spyOn(observable,'subscribe').and.returnValue(receivedHttpEvent); 将不起作用,因为 subscribe 返回订阅并且 receivedHttpEvent 应该由 observable 发出。
  • 谢谢马丁。我想我的疑问是如何让 observable.subscribe((res)=>... receivedHttpEvent. 一起运行。我无法弄清楚。
  • 看看这个 github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/… 或者如果你能做一个stackblitz演示我可以看看
  • 谢谢马丁。我尝试了另一种方法。感谢您向我介绍 Marbel 测试。我不知道。我还发现这篇文章很有用 - medium.com/angular-in-depth/…
  • Martin =-我想尝试使用 marbel 测试来模拟错误场景,但我被卡住了。请看一下 stackoverflow.com/questions/61337404/…

【解决方案1】:

我这样做了(希望这是正确的方法)。测试的范围是检查 Subject next 是否被正确调用。因此,使用 of 创建一个 Observable 并让代码从那里流出。

fit('should call send next value for the subject is the response from the server is ok', () => {
  const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
  const helperService:HelperService = TestBed.get(HelperService);
  const body = {"result":"success", "additional-info":"some additional info"};
  const receivedHttpEvent = new HttpResponse({body:body});
  const expectedResult = new Result('success', 'some additional info');
  spyOn(helperService,'validateServerResponseStructure').and.returnValue(true);
  let observable = of(receivedHttpEvent);
  spyOn(questionService['editQuestionSubject'],'next');
  questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
  expect(questionService['editQuestionSubject'].next).toHaveBeenCalledWith(expectedResult);
});

【讨论】: