1

I am learning testing Angular 2 with Karma, and was wondering about some points in code I didn't understand. After the TestBed "mock module" is configured, the following code runs:

    mockBackend = getTestBed().get(MockBackend);

What does this do? I found the following explanation in another article: "gets a reference to the mock backend so we can respond with fake data when it is fetched with Http.get", but I don't see why I need to "get it", isn't it already there from import {MockBackend, MockConnection} from '@angular/http/testing';? Or does the module get the method somehow?

I use it later like so...and still don't understand why I had to attach it to the test bed:

    mockBackend.connections.subscribe(
        (connection: MockConnection) => {
            connection.mockRespond(new Response(
                new ResponseOptions({
                        body: "lol data"
                    }
                )));
        });

In short, the actual question is - what does the first line of code I posted do?

Complete code, just for context:

import { TestBed, getTestBed, async, inject } from '@angular/core/testing';
import { Headers, BaseRequestOptions, Response, HttpModule, Http, XHRBackend, RequestMethod} from '@angular/http';

import {ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';
import {FooHttpService} from '../../services/foo-service.service.ts';


describe('My Service Making an Http Call', () => {

    let mockBackend: MockBackend;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            providers: [
                FooHttpService,
                MockBackend,
                BaseRequestOptions,
                {
                    provide: Http,
                    deps: [MockBackend, BaseRequestOptions],
                    useFactory:
                        (backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
                            return new Http(backend, defaultOptions);
                        }
                }
            ],
            imports: [
                HttpModule
            ]
        });

        mockBackend = getTestBed().get(MockBackend);
        TestBed.compileComponents();
    }));

Code is taken from a tutorial here.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
VSO
  • 11,546
  • 25
  • 99
  • 187

1 Answers1

2

isn't it already there from import {MockBackend, MockConnection} from '@angular/http'

This only give you access to the symbol/class. Just like if you want to use a service in your component, you need to import the service into the component file

import { SomeService } from './some.service'

class SomeComponent {
  constructor(service: SomeService) {}
}

If we didn't import SomeService, we would get an error "can't find symbol SomeService". But this is just a compile-time check. This is not enough to use an instance of the service as runtime. If this was all we had, at runtime, we would get the error "no provider for SomeService". We still need to add if to the providers so that Angular knows to create it, and pass the instance to the component at runtime

import { NgModule } from '@angular/core';
import { SomeService } from './some.service';
import { SomeComponent } from './some.component';

@NgModule({
  declarations: [ SomeComponent ],
  providers: [ SomeService ]
})
class SomeModule {}

Here is the same thing, we need to import the component symbol/class into the module file so that we can use the symbol/class in that file.

As far as the MockBackend, you add the class to the providers

providers: [ MockBackend ]

This tells Angular to create the instance, allowing it to be injectable. You then inject the instance created By Angular, into the factory method

useFactory: (backend: MockBackend, options: BaseRequestOptions) => {
  return new Http(backend, options);
}

Now Http will use that instance of the MockBackend when we make requests. But we need access to that same instance so that we can mock the response. In order to get it, we need to get it from Angular injector (which is the container for all the providers). To access the injector during the test, we can go through the TestBed, which acts like an injector for the test environment

mockBackend = TestBed.get(MockBackend);

Here we are asking Angular to look in its injector for a provider MockBackend. This will be the same instance that is injected into the useFactory function. So we insure that we mock the responses on the same MockBackend instance that the Http is using.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720