Unit testing with private service injected using jasmine angular2

巧了我就是萌 提交于 2020-01-02 02:21:26

问题


I have a problem trying to unit test an angular service. I want to verify that this service is properly calling another service that is injected into it.

Lets say I have this ServiceToTest that injects ServiceInjected:

ServiceToTest .service.ts

@Injectable()
export class ServiceToTest  {
    constructor(private _si: ServiceInjected) {}
    public init() {
      this._si.configure();
    }

}

ServiceInjected.service.ts

@Injectable()
export class ServiceInjected {
    constructor() {}
    public configure() {
    /*Some actions*/
    }

}

With these services, now I write my unit test:

const serviceInjectedStub = {
  configure(): void {}
}


describe('ServiceToTest service Test', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [ServiceToTest ,
        { provide: ServiceInjected, useValue: serviceInjectedStub }]
    });
  });
  
  it('should be initialize the service injected', inject([ServiceToTest],
    (tService: ServiceToTest) => {
      spyOn(serviceInjectedStub, 'configure');
      tService.init();
      expect(serviceInjectedStub.configure).toHaveBeenCalled();
    }));

I expected my test to be positive, however I receive the following error:

Expected spy configure to have been called.

On the other hand, it works OK if I set the injected service public in this way:

private _si: ServiceInjected by public si: ServiceInjected

回答1:


You don't spy on the service tied to your TestBed. Get the service from your Testbed

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [ServiceToTest ,
      { provide: ServiceInjected, useValue: serviceInjectedStub }]
  });
  injectedService = TestBed.get(ServiceInjected);
});

And test on it

spyOn(injectedService, 'configure').and.returnValue(/* return same data type here */);
// ...
expect(injectedService.configure).toHaveBeenCalled();



回答2:


Or you can use jasmine.createSpyObj and provide it with useValue like bellow:

describe('YourComponent', () => {

  let serviceInjectedSpy: jasmine.SpyObj<ServiceInjected>;

  beforeEach(async(() => {

     // notice here
     serviceInjectedSpy = jasmine.createSpyObj('ServiceInjected', ['configure']);

     TestBed.configureTestingModule({
        declarations: [YourComponent],
        providers: [
           {provide: ServiceInjected, useValue: serviceInjectedSpy}
        ],
        imports: [
         ...
        ]
     }).compileComponents().then(() => {
        fixture = TestBed.createComponent(YourComponent);
        component = fixture.componentInstance;
     });
  });

  it('should assert my test', () => {
       serviceInjectedSpy.configure.and.returnValue(/* what you want */);
       component.init();
       expect(serviceInjectedSpy.configure).toHaveBeenCalled();
  });

});



回答3:


Use this:

spyOn(serviceInjectedStub, 'configure').and.returnValue(config); // config is a mock




回答4:


You should use a mock service like:

class MockAuthService extends AuthService {
  isAuthenticated() {
    return 'Mocked';
  }
}

In this way you have control over the service that you are not testing and focus on the other.

Now, to check if the service is being called correctly maybe you can add a mock variable that is turned to true whenever the mock service is called.



来源:https://stackoverflow.com/questions/47938424/unit-testing-with-private-service-injected-using-jasmine-angular2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!