Faking a module in angular 2 test

2019-08-02 21:34发布

问题:

I have a function in angular 2 service which I would like to test.

service.ts

upload(){
  let file = new Transfer();
  file.upload(myfile).then( // my callback );
}

I would like to mock Transfer in my test using jasmine. I tried this in my

sevice.spec.ts

import { TransferMock as Transfer } from '../mocks/mocks' to mock it. But it is not working. This is how my test is instantiated .

describe('authentication service' , () => {
  beforeEach(() => {
    auth = new Service(<any>new HttpMock(), <any>new StorageMock())
  });
  it('initialize authentication',() => {
    expect(auth).not.toEqual(null);
    auth.upload('file'); //it fails here
  });
})

edit

Transfer is not injected in the service. Only one function uses Transfer . So not injecting can reduce the initial loading time of the app i guess(would be happy to know other opinions) . So I would like to know if there is anyway to mock if its constructed this way ?

edit

Although I had accepted Martin's answer as it is the best practice, it has one issue which can happen when you use ionic-native plugins.If the plugin doesnt have browser support it can fail. In this case it happened when I inject it, with error FileTransfer is not defined . So I am back again, looking for suggestions.

回答1:

In order to provide a mock for a class in a test, you need to inject the class in your implementation.

In your ngModule add Transfer to your providers. Then simply inject it into your service.

Then in your test you can use { provide: Transfer, useClass: TransferMock } in your TestBed providers.

Update

The primary purpose of Dependency Injection is to make code testable and to allow mocking - faking - stubbing of services.

Update

With Dependancy Injection you can configure a different set of providers for different environments.

For example, if you are running your application in the browser, and in a native mobile environment you can swap out your configuration.

In your module you could have something like this:

const TRANSFER_PROVIDER: any;

if (environment.browser) {
  TRANSFER_PROVIDER = Transfer;
} else {
  TRANSFER_PROVIDER = { provide: Transfer, useClass: NativeTransfer }
}

...
providers: [ TRANSFER_PROVIDER ]

NativeTransfer could be a simple stub that does nothing but prevent errors, or it could let the user know that this feature is not supported in their browser.