我想测试我的一个辅助函数是否在http服务层中被调用,但我得到了一个失败的测试。我是新手,所以请告诉我我做错了什么
服务层
public customerUpload(
file: Blob,
name?: string): Observable<CustomerResponse> {
if (name!== '') {
parameters = addQueryPara(name, 'name');
}
return this.http.post(file, parameters)
)
我想检查如果我用name调用CustomerUpload,它应该调用addQueryPara
My Spec file Test
import * as helper from 'app/shared/helper.ts';
describe('customerService', () => {
let service: customerService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
});
service = TestBed.inject(customerService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('when customer is called', () => {
beforeEach(() => {
const response = getMockResponse();
jest.spyOn(service, 'customerUpload').mockReturnValue(of(response) as any);
});
it('should add http params', () => {
service.customerUpload(new Blob(), 'learn');
expect(jest.spyOn(helper, 'addQueryPara')).toHaveBeenCalledTimes(1); // This is failing
});
});
});
addQueryPara失败。如何确保传递参数时,它会调用addQueryPara?
首先,您应该导入要测试的服务,以便稍后注入。在这种情况下,因为你需要模拟HttpClient
,所以它不会发出任何真正的请求,你可以用TestBed
和HttpClientTestingModule
来做(这里是jasmine的官方Angular文档,但它是相似的)。
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CustomerService } from './customer.service.ts'; // change this to the name of your route
describe('CustomerService', () => {
let service: CustomerService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [CustomerService] // <- Here we import the real service
});
service = TestBed.inject(CustomerService);
});
然后,在您的测试中,我看到您试图模拟HTTP POST请求。为此,你可以使用HttpTestingController
,这是HttpClientTestingModule
的一部分(在这里你有一个关于用Angular测试HTTP的很好的教程)。
describe("when customerUpload is called", () => {
const mockFile = // your mock
afterEach(() => {
// After every test, assert that there are no more pending requests.
httpTestingController.verify();
});
it("should invoke HTTP POST with the file", () => {
service.customerUpload(mockFile);
// Check for correct requests: should have made one request to POST search from expected URL
const req = httpTestingController.expectOne(customerUrl); // the url you expect to be called, including the queryParams, e.g.: customerUrl:4200?name=Mario
expect(req.request.method).toEqual("POST");
// Provide each http request with a mock response
req.flush(getMockResponse());
});
});
这是单元测试理论:如果addQueryPara
函数没有导出到这个服务之外,你不应该显式地测试它。只需测试name !== ''
customerUpload
的结果是否如您所期望的那样工作另外,我不确定上传文件的实现,你应该看看这个评论。
我不知道jest
,但我想当你做jest.spyOn(...).mockReturnValue(...)
时,你正在存根方法并失去mockReturnValue
的实现细节。
另一件事是,你是在调用方法之后监视,但你应该在调用方法之前监视。
我将首先使用HttpClientTestingModule
而不是真正的HttpClientModule
进行测试,因此实际的API调用不会发送,您可以断言发送了哪些API调用。
试着移除mockReturnValue
,看看它是否通过。
import * as helper from 'app/shared/helper.ts';
describe('customerService', () => {
let service: customerService;
beforeEach(() => {
TestBed.configureTestingModule({
// !! Change to HttpClientTestingModule
imports: [HttpClientTestingModule],
});
service = TestBed.inject(customerService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('when customer is called', () => {
beforeEach(() => {
const response = getMockResponse();
!! remove mockReturnValue
jest.spyOn(service, 'customerUpload');
});
it('should add http params', () => {
// !! move this up before calling the method so we are actually spying before
const addSpy = jest.spyOn(helper, 'addQueryPara');
service.customerUpload(new Blob(), 'learn');
// !! assert now
expect(addSpy).toHaveBeenCalledTimes(1);
});
});
});
查看此链接以测试HTTP服务:https://testing-angular.com/testing-services/#testing-a-service-that-sends-http-requests
它使用了Karma和Jasmine而不是Jest,但是思想是一样的。
首先需要删除以下行:
jest.spyOn(service, 'customerUpload').mockReturnValue(of(response) as any);
正如AliF50所提到的,通过这样做,你完全模仿了service.customerUpload
的内部行为,因此实际的实现将永远不会被调用,它将始终返回of(response)
。
此外,您可能希望将HttpClientModule
的导入更改为HttpClientTestingModule
,以便在您发出任何http请求(如this.http.post
;
)时能够轻松地模拟和监视。这是你的代码看起来像(我假设addQueryPara
是一个错别字,但没有改变它与您的示例一致):
import * as helper from 'app/shared/helper.ts';
import { customerService } from './customer-service';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
describe('customerService', () => {
let service: customerService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
});
service = TestBed.inject(customerService);
httpMock = TestBed.inject(HttpTestingController);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('when customer is called', () => {
it('should add http params', () => {
// Given.
const mockFile = new Blob();
const mockName = 'learn';
const addQueryParaSpy = jest.spyOn(helper, 'addQueryPara');
// When.
service.customerUpload(mockFile, mockName);
// Then.
expect(addQueryParaSpy).toHaveBeenCalledWith(mockName, 'name');
});
});
});