【问题标题】:spyOn not working in Http Interceptor in Angular 6spyOn 在 Angular 6 的 Http 拦截器中不起作用
【发布时间】:2019-04-22 10:49:32
【问题描述】:

我正在尝试测试记录 http 请求响应的 HttpInterceptor。我有一个记录请求响应的日志服务。拦截器仅记录 GET 请求。

这是我的拦截器:

import { HttpInterceptor, HttpHandler, HttpEvent, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { LogService } from './log.service';
import { Injectable } from '@angular/core';

@Injectable({providedIn: 'root'})
export class LoggerInterceptor implements HttpInterceptor {

  constructor(private _log: LogService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
      .pipe(
        tap(event => {
          if (event instanceof HttpResponse) {
            if (req.method === 'GET') {
              this._log.log('I was logged');
            }
          }
        })
      );
  }
}

这是规范文件:

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController, TestRequest } from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { HeaderInterceptor } from './add.header.interceptor';
import { LogService } from './log.service';
import { LoggerInterceptor } from './logger.interceptor';

const posts: Array<any> = [
  {
    'userId': 1,
    'id': 1,
    'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
    'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et '
  },
  {
    'userId': 1,
    'id': 2,
    'title': 'qui est esse',
    'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor b'
  }
];

describe('HeaderInterceptor', () => {

  let httpMock: HttpTestingController;
  let logService: LogService;
  let httpClient: HttpClient;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [
        LogService,
        { provide: HTTP_INTERCEPTORS, useClass: LoggerInterceptor, multi: true }
      ]
    });

    httpMock = TestBed.get(HttpTestingController);
    logService = TestBed.get(LogService);
    httpClient = TestBed.get(HttpClient);
  });

  it('must log the http get request', () => {

    const spy = spyOn(logService, 'log');

    httpClient.get('http://jsonplaceholder.typicode.com/posts')
      .subscribe(
        (data: Array<any>) => {
          expect(data.length).toBe(2);
        }
    );

    const req: TestRequest = httpMock.expectOne('http://jsonplaceholder.typicode.com/posts');
    expect(req.request.headers.has('Content-Type')).toBe(true);
    expect(spy).toHaveBeenCalled();

    req.flush(posts);
  });

  it('must log the http post request', () => {

    const spy = spyOn(logService, 'log');

    httpClient.post('http://jsonplaceholder.typicode.com/posts', posts)
      .subscribe();

    const req: TestRequest = httpMock.expectOne('http://jsonplaceholder.typicode.com/posts');
    expect(req.request.headers.has('Content-Type')).toBe(true);
    expect(spy).not.toHaveBeenCalled();

    req.flush(posts);
  });
});

我有 HeaderInterceptor 将 Content-Type 标头添加到每个 http 请求。对该拦截器的测试工作正常。

当我尝试测试 LoggerInterceptor 时,我在 spy expect(spy).toHaveBeenCalled(); 上收到错误消息

这是错误:

Error: Expected spy log to have been called.
    at stack (http://localhost:9876/absolute/home/pritambohra/Desktop/testing-in-angular/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:2455:17)
    at buildExpectationResult (http://localhost:9876/absolute/home/pritambohra/Desktop/testing-in-angular/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:2425:14)
    at Spec.expectationResultFactory (http://localhost:9876/absolute/home/pritambohra/Desktop/testing-in-angular/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:901:18)
    at Spec.addExpectationResult (http://localhost:9876/absolute/home/pritambohra/Desktop/testing-in-angular/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:524:34)
    at Expectation.addExpectationResult (http://localhost:9876/absolute/home/pritambohra/Desktop/testing-in-angular/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:845:21)
    at Expectation.toHaveBeenCalled (http://localhost:9876/absolute/home/pritambohra/Desktop/testing-in-angular/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:2369:12)
    at UserContext.<anonymous> (http://localhost:9876/src/app/logger.interceptor.spec.ts?:57:17)
    at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/node_modules/zone.js/dist/zone.js?:388:1)
    at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:288:1)
    at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/node_modules/zone.js/dist/zone.js?:387:1)

不太确定我哪里出错了。为了代码覆盖,我正在执行 post http 调用。我需要解决什么问题?

【问题讨论】:

    标签: angular unit-testing karma-jasmine angular-http-interceptors


    【解决方案1】:

    这可能只是部分答案。

    我不是测试专家,所以我不应该试图解释为什么您的代码会失败,但我相信下面的代码是正确的并且可以进行真正的测试。

    IMO 在 GET 案例中您的代码存在两个问题: - 在期待间谍之后你正在冲洗 - 应该是相反的方式 - 你不是从.subscribe() 内部调用done()

    您的 POST 案例代码似乎可以正常工作(除了测试描述似乎不正确,不应该改为“不应该记录”吗?)

    我没有检查 Content-Type 标头,因为它由于某种原因失败(没有时间进一步调查它 - 很想知道你是否解决了它)而且它不是你问题的一部分.

    describe('Logger Interceptor', () => {
      let httpMock: HttpTestingController;
      let httpClient: HttpClient;
      let logService: LogService;
      let spy: Function;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [HttpClientTestingModule],
          providers: [
            {
              provide: HTTP_INTERCEPTORS,
              useClass: LoggerInterceptor,
              multi: true,
            },
          ],
        });
    
        httpClient = TestBed.get(HttpClient);
        httpMock = TestBed.get(HttpTestingController);
        logService = TestBed.get(LogService);
        spy = spyOn(logService, 'log');
      });
    
      afterEach(() => httpMock.verify());
    
      it('must log the http get request', (done) => {
    
        httpClient.get('http://jsonplaceholder.typicode.com/posts').subscribe((data: any[]) => {
          expect(data.length).toBe(2);
          done();
        });
    
        const req: TestRequest = httpMock.expectOne('http://jsonplaceholder.typicode.com/posts');
    
        req.flush(posts);
        expect(spy).toHaveBeenCalled();
      });
    
      it('should NOT log the http post request', () => {
    
        httpClient.post('http://jsonplaceholder.typicode.com/posts', posts)
          .subscribe();
    
        const req: TestRequest = httpMock.expectOne('http://jsonplaceholder.typicode.com/posts');
        expect(spy).not.toHaveBeenCalled();
    
        req.flush(posts);
      });
    });
    

    我很想知道为什么 GET 案例需要进行上述更改,如果有人能够解释的话。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2019-08-03
      • 2018-01-07
      相关资源
      最近更新 更多