3

我正在做一个 Angular 5 项目,这没什么大不了的。虽然我从 2.1/2.2 早期就退出了 Angular2+ 业务。

所以我有这个调用公共 API 的服务,但是我的测试一直失败:Error: Expected one matching request for criteria "Match URL: http://api.icndb.com/jokes/random/10", found none.

代码:

fact.service.spec.ts

import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
import {TestBed, inject} from "@angular/core/testing";
import {FactService} from "./fact.service";
import {Fact} from "../models/fact";
import {FactHttpResponse} from "../models/factHttpResponse";

describe("FactService", () => {
    let factService: FactService;
    let httpMock: HttpTestingController;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [FactService],
        });
        httpMock = TestBed.get(HttpTestingController);
        factService =  TestBed.get(FactService);
    });

    // TODO: Something is going wrong with this test get some help online
    it("Should be able to retrieve Facts in subscription when calling loadFacts", (done) => {
    const factList: Fact[] = [
        {id: 1, joke: "a"},
        {id: 2, joke: "a"},
    ];

    const factResponse: FactHttpResponse = { value: factList};

    factService.subscribe(val => {
        expect(val).toEqual(factList);
        done();
    });

    const mockRequest = httpMock
        .expectOne(factService.CHUCK_NORRIS_API.replace("{count}", "10"));
    expect(mockRequest.request.method).toEqual('GET');

    factService.loadFacts();

    mockRequest.flush(factResponse);
});

afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
    httpMock.verify();
}));
});

事实.service.ts

 import { HttpClient } from "@angular/common/http";
 import { Injectable } from "@angular/core";
 import { Subject } from "rxjs/Subject";

 import {Fact} from "../models/fact";
 import {FactHttpResponse} from "../models/factHttpResponse";

@Injectable()
export class FactService {

// public for testing purposes
public readonly CHUCK_NORRIS_API = "http://api.icndb.com/jokes/random/{count}";
private factSubject = new Subject();
private facts: Fact[] = [];
private favorites: Fact[] = [];

constructor(private http: HttpClient) { }

public subscribe(callback: (value: Fact[]) => void) {
    return this.factSubject.subscribe(callback);
}

public loadFacts(count = 10) {
    this.http.get<FactHttpResponse>(this.CHUCK_NORRIS_API.replace("{count}", count.toString()))
        .subscribe(data => {
           if (data.value) {
               this.facts = data.value
                   .map(f => {
                       f.favorite = !!this.favorites.find(fav => fav.id === f.id);
                       return f;
                   });
               this.factSubject.next(this.facts);
           }
        });
}
}

该代码实际上有效,但我似乎无法对其进行测试:-(。如果我删除 verifyOne 它实际上抱怨对错误中提到的完全相同的 url 的打开请求。

4

1 回答 1

8

由于factService.loadFacts()生成 HTTP 请求的是您的方法,因此您的测试的最后三个部分是乱序的。它应该是(带评论):

describe(..., () => {
    it(..., () => {
        ...

        // queue up the http request in the mockHttp request queue
        factService.loadFacts();

        // verify that there is now one (and only one) request queued up
        const mockRequest = httpMock
            .expectOne(factService.CHUCK_NORRIS_API.replace("{count}", "10"));
        expect(mockRequest.request.method).toEqual('GET');

        // satisfy the pending request in the mockHttp request queue
        mockRequest.flush(factResponse);
    });

    // Bonus tip: you already have mockHttp in the describe() scope.  Simplify:
    afterEach(() => {
        // verify there are no unsatisfied requests in the mockHttp queue
        httpMock.verify();
    });
});
于 2017-12-13T22:28:25.403 回答