Solvedangular Provide a mock service using TestBed

I'm submitting a ... (check one with "x")

[ x] bug report

Current behavior
TestBed providers looks for the dependencies of my original service although my mocked service have none of them.
And sometimes when running the test I get:
This test module uses the component DummyRestApiComponent which is using a "templateUrl", but they were never compiled. Please call "TestBed.compileComponents" before your test.
Although I am calling TestBed.compileComponents.

Expected/desired behavior
Before RC5 addProviders used the mock without looking for its dependencies which reduces the knowledge the component in test knows about the service.

Reproduction of the problem

    TestBed.configureTestingModule({
      declarations: [DummyRestApiComponent],
      providers: [
        // ConfigurationService,
        {provide: DummyRestApiService, useClass: MockDummyRestApiTestService},
        DummyRestApiComponent,
      ],
      imports: [FormsModule, HttpModule]
    });

Vs The old way

addProviders([
       DummyRestApiComponent,
       {provide: DummyRestApiService, useClass: MockDummyRestApiTestService},
     ]);

No need for configuration Service.

Before each test I am using

 beforeEach(async(() => {
      TestBed.compileComponents().catch(error => console.error(error));
    }));

And when testing

 it('should create an instance', async(() => {
        var fixture = TestBed.createComponent(DummyRestApiComponent);
        fixture.detectChanges();
        expect(fixture.debugElement.componentInstance).toBeTruthy();
      }
    ));
  • Angular version: 2.0.0-rc.5

Using Karma + Jasmine (Angular CLI 1.0.0-beta.10)

  • Language: [Typescript]
39 Answers

✔️Accepted Answer

I was having this issue as well, however I noticed that my @component metadata still had the providers array defined. Moving this providers array into my applications @NgModule solved this issue for me.

From what I've seen so far, there is no way to override (mock) a provider specified in a @component metadata.

Other Answers:

@timshelley From what I understand, declaring providers on the component level is still supported and useful, so moving them to the module level seems like changing your implementation just to make the test work, which I didn't want to do. This works for me with rc.6:

TestBed.overrideComponent(MyComponent, {
  set: {
    providers: [{ provide: SomeService, useValue: myMock }]
  }
});

With the current state of documentation around testing, it is a really frustrating exercise to come up with decent solutions for non-trivial cases. I hope this changes soon.

Using overrideComponent worked for me (I had called it wrong), but setting the providers with TestBed.configureTestingModule is broken.

Here is the code for clarity: -

TestBed.configureTestingModule({
      imports: [FormsModule, HttpModule],
      declarations: [LoginComponent],
    }).overrideComponent(LoginComponent, {
      set: {
        providers: [
          {provide: AuthenticationService, useValue: authServiceMock},
          {provide: Router, useValue: routerStub}
        ]
      }}
      ).compileComponents();

Thanks for the tip @chris-jones-pixitmedia

I can confirm that I was able to mock a service with TestBed as well. Here's a code snippet:

describe('Component: Search', () => {
  let mockSearchService: MockSearchService;
  let mockActivatedRoute: MockActivatedRoute;
  let mockRouter: MockRouter;

  beforeEach(() => {
    mockSearchService = new MockSearchService();
    mockActivatedRoute = new MockActivatedRoute({'term': 'peyton'});
    mockRouter = new MockRouter();

    TestBed.configureTestingModule({
      declarations: [SearchComponent],
      providers: [
        {provide: SearchService, useValue: mockSearchService},
        {provide: ActivatedRoute, useValue: mockActivatedRoute},
        {provide: Router, useValue: mockRouter}
      ],
      imports: [FormsModule]
    });
  });
});

I've also used useClass with success:

beforeEach(() => {

  TestBed.configureTestingModule({
    providers: [
      {
        provide: Http, useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => {
        return new Http(backend, defaultOptions);
      }, deps: [MockBackend, BaseRequestOptions]
      },
      {provide: SearchService, useClass: SearchService},
      {provide: MockBackend, useClass: MockBackend},
      {provide: BaseRequestOptions, useClass: BaseRequestOptions}
    ]
  });
});

I wrote up a tutorial on using the new testing infrastructure in RC5 since there doesn't seem to be much documentation available.

http://gist.asciidoctor.org/?github-mraible%2Fng2-demo%2F%2FREADME.adoc

@AshMcConnell I don't think it's broken. If you declare the providers in @NgModule, you provide the mock using configureTestingModule. If you declare the providers in @Component, you provide the mock using overrideComponent. As discussed above: #10727 (comment), #10727 (comment)

More Issues: