问题
I am trying to mock some http requests while testing my Angular app. I am following popular examples over the internet that uses fakeBackendProvider by utilizing Angular's MockBackEnd and MockConnection. Though I understand the code well I would like to understand more in-detail the internal working of these providers.
How do they intercept http requests? For instance when my code make calls to http.get() who gets hooked to what, who replaces what, and how?
Any reference material would be highly helpful.
回答1:
Try HttpClient which is new from angular 4.3.X. It provides easy way to implement the HttpInterceptor. To intercept,
Use HttpInterceptor interface that has a method Intercept which you will have to override in your class. a sample code as given below,
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/Observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/Observable/of';
import 'rxjs/add/operator/do';
export class YourInterceptor implements HttpInterceptor{
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>{
// Your interceptor code comes here.
// you wish to change the request, change here.
request = request.clone({
setHeaders: {
Authorization: `Bearer ${this.auth.getToken()}`
}
});
return next.handle(request);
}
}
I think you are trying to write unit testing also for the same, in order to do so
Angular 4 provides two awesome classes to work with HttpTestingController, HttpClientTestingModule. Make sure you provide HttpClientModule in the module.ts file before using this.
import { TestBed, inject, getTestBed } from '@angular/core/testing';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { HttpTestingController, HttpClientTestingModule } from '@angular/common/http/testing';
import { YourService } from './get-name-service.service';
describe('YourService', () => {
let injector: TestBed;
let httpMock: HttpTestingController;
let yourService: YourService;
beforeEach(() => {
TestBed.configureTestingModule({
imports:[HttpClientTestingModule],
providers: [YourService]
});
injector = getTestBed();
httpMock = injector.get(HttpTestingController);
yourService = TestBed.get(YourService);
});
describe('#getUsers', () => {
it('should return an Observable<User[]>', () => {
const dummyUsers = [
{ login: 'John' },
{ login: 'Doe' }
];
yourService.getNames().subscribe(users => {
console.log('I am here in yourService method');
expect(users.length).toBe(2);
expect(users).toEqual(dummyUsers);
});
const req = httpMock.expectOne('http://localhost:8080/dev/getNames');
expect(req.request.method).toBe("GET");
req.flush(dummyUsers);
});
});
});
回答2:
For mockbackend, you can do something like this,
Include correct provider in your application as given below, in your case it will be Http. ...Provider:[Http, ...]
Your test file will house following codes or configuration, in this if you notice we have used ReflectiveInjector class and a method resolveAndCreate. This method will help you create an object of a required class with all its dependencies. ex this.yourService = this.injector.get(YourService);
following two lines will help your test code to connect with the fake backend
{provide: ConnectionBackend, useClass: MockBackend},
{provide: RequestOptions, useClass: BaseRequestOptions},
provide and useClass, now whenever your ConnectionBackend class object is created it would be mapped with MockBackend class object,
Now each of the test case for an example it('getNames() should return some names', can use this.lastConnection will be utilized to connect with your mockedbackend, there you will have to create a Response by using Response and ResponseOptions class as given below in the code snippet below.
describe('MockBackend NameService Example', () => {
beforeEach(() => {
this.injector = ReflectiveInjector.resolveAndCreate([
{provide: ConnectionBackend, useClass: MockBackend},
{provide: RequestOptions, useClass: BaseRequestOptions},
Http,
YourService,
]);
this.yourService = this.injector.get(YourService);
this.backend = this.injector.get(ConnectionBackend) as MockBackend;
this.backend.connections.subscribe((connection: any) => this.lastConnection = connection);
});
it('getNames() should return some names', fakeAsync(() => {
let result: String[];
this.yourService.getNames().then((names: String[]) => result = names);
this.lastConnection.mockRespond(new Response(new ResponseOptions({
body: JSON.stringify({data: ["Deepak Test1", "Deepak Test2"]}),
})));
tick();
expect(result.length).toEqual(2, 'should contain given amount of Names');
expect(result[0]).toEqual("Deepak Test1", ' NAME_ONE should be the first Name');
expect(result[1]).toEqual("Deepak Test2", ' NAME_TWO should be the second Name');
}));
});
来源:https://stackoverflow.com/questions/47090244/understanding-angulars-fakebackendprovider-mockbackend-and-mockconnection