Angular - 使用 Jasmine 监视 HttpClient 中的链式方法

Angular - Use Jasmine to spy on chained methods within HttpClient

我有一种情况需要监视在调用另一个方法之后调用的方法。

这是正在测试的 class/method:

@Injectable()
export class SomeService {

  constructor(private customHttpClient: CustomHttpClient) {
  }

    updateSomethingCool(signerVO: SignerVO): Observable<SignerVO> {

    // ...

    return this.customHttpClient.withCustomOverrides(new CustomErrorHandlerHttpInterceptorOverride({ passthroughStatusCodes: [BAD_REQUEST, BAD_GATEWAY] }))
        .put<SignerVO>(`/my/url/goes/here`, signerVO);
    }
}

此 class 使用 CustomHttpClient,如下所示:

    @Injectable()
    export class CustomHttpClient extends HttpClient {
        private interceptors: HttpInterceptor[] | null = null;

        constructor(private injector: Injector,
            originalHandler: HttpHandler, private originalBackend: HttpBackend) {
            super(originalHandler);
        }

        public withCustomOverrides(...overrides: CustomHttpInterceptorOverride[]): HttpClient {

            // do very customizable things here

            return new CustomDelegatingHttpClient(
                new CustomHttpInterceptingHandler(this.originalBackend, this.interceptors, overrides));
        }
    }

    export class CustomDelegatingHttpClient extends HttpClient {
        constructor(private delegate: HttpHandler) {
            super(delegate);
        }
}

这是我的单元测试尝试,确实调用了 put 方法,因此我需要监视 put 方法:

describe(SomeService.name, () => {
let service: SomeService;
let customHttpClient: CustomHttpClient;

let emptySignerVO: SignerVO = new SignerVO();

beforeEach(() => {
    customHttpClient= <CustomHttpClient>{};
    customHttpClient.put = () => null;
    customHttpClient.withCustomOverrides = () => null;

    service = new SomeService(customHttpClient);
});

describe('updateSomethingCool', () => {

    it('calls put', () => {
        spyOn(customHttpClient, 'put').and.stub();

        service.updateSomethingCool(emptySignerVO);

        expect(customHttpClient.put).toHaveBeenCalled();
    });
});

现在很清楚,当我 运行 收到此失败消息时:

TypeError: Cannot read property 'put' of null

但是,我不知道如何在测试的 beforeEach 部分中定义 putwithCustomOverrides 方法。

请注意,CustomHttpClient 只是 Angular 的 HttpClient 的自定义包装器 class,允许一些更详细的功能。

感谢您的帮助!

我认为你应该注入 httpClient ;

beforeEach((http: HttpClient) => {
  httpClient = http;
  httpClient.put = () => null;
  httpClient.withCustomOverrides = () => null;
  service = new SomeService(log, httpClient);});

您是否使用 Angular 依赖注入将 HttpClient 注入 CustomHttpClient?当测试依赖于 HttpClient 的服务时,您可以使用 HttpTestingController,对于服务单元测试,这可能如下所示:

it(`should get a new data instance of type T`, 
  async(inject([TestDataService, HttpTestingController],
  (service: TestDataService, backend: HttpTestingController) => {
    // ... tests here
  })
));

好吧,最后我实际上并没有那么远。实际测试代码没问题; beforeEach() 方法需要更新如下:

beforeEach(() => {
    customHttpClient = <CustomHttpClient>{};
    customHttpClient.put = () => null;
    customHttpClient.withCustomOverrides = () => customHttpClient;

    service = new SomeService(customHttpClient);
});

我基本上只需要将 customHttpClient 对象分配给 .withCustomOverides 方法。

如果您查看实际调用中方法链接的流程,这实际上是有道理的。