angularunit-testingtypescriptkarma-jasminetestbed

TypeError: undefined is not a constructor (evaluating 'this.service.getDat().subscribe')


I am working on an angular 4 Application, writing Unit Cases, I am facing below Problem.

component.ts

 ngOnInit() {
    this.service.getData().subscribe(res => {
      console.log(res);
      this.data= JSON.parse(res._body);
      this.addFormControls();
    },
      error => {
        console.log(error);
      });
  }

component.spec.ts

 describe('component', () => {

      let userRolesService: LayoutService;
      const modulesData = {
        'moduleName':'Info'
      }
      class MockUserRolesService {
        public getModulesData() {
            return modulesData;
        }
      }
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          providers:[ {provide: LayoutService, useClass: MockUserRolesService } ]
        })
        .compileComponents();
      }));

      beforeEach(() => {
        userRolesService = TestBed.get(LayoutService);

      });
      afterEach(() => {
        userRolesService = null;
       component = null;
     });


        it('should fetch module data', () => {

        userRolesService.getData().subscribe(
          result => {
          expect(result).toBeTruthy();
          }
      );
      });
    });

Updated the code for mock services file.Could you please help me some one to make it work. Used Mock service and test Bed Framework. Could you please some one help me..................................................................................................................................................................................................................................................................................................................................................


Solution

  • I don't know what you tried to mock, but that's not how you mock a service.

    I will use the useValue instead of the useClass, but you can adapt it if you want.

    Your test is testing a subscription to an observable, and you return ... Nothing.

    class MockUserRolesService {
      public getModulesData() {
        return modulesData;
      }
    }
    

    You're testing getData and I don't see it anywhere in your mock.

    Here is how you mock your service.

    const serviceMock = {
      provide: LayoutService,
      useValue: {
        getData: Observable.of(/* any value you want */)
      }
    };
    
    TestBed.configureTestingModule({
      providers:[ {provide: LayoutService, useValue: serviceMock } ]
    })
    

    EDIT In unit testing, you test if your features (components, services) work as expected. let's take your ngOnInit function for instance :

    this.service.getData().subscribe(res => {
      console.log(res);
      this.data= JSON.parse(res._body);
      this.addFormControls();
    }
    

    Given how you wrote it, your tests should cover this cases :

    If you want to test that, you should create this mock :

    useValue: {
      getData: Observable.of({
        '_body': 'my data'
      })
    }
    

    Now, you must make your test. Since you have an asynchronous call (with an Observable), then you should subscribe to the call, then call. Here is how it's done.

    it('should call the getData function of the service and store the data', () => {
      // Spy on your service to see if it has been called, and let him process
      spyOn(component['service'], 'getData').and.callThrough();
      // Array notation avoid scope issues (if your variable is protected or private)
      component['service'].getData().subscribe(response => {
        expect(component['service'].getData).toHaveBeenCalled();
        // Since you store the data in the data variable, check if it's equal to your mock value
        expect(component.data).toEqual('my data');
      });
    });
    

    If you want to test all cases :

    it('should call the getData function of the service and store the data', () => {
      spyOn(component['service'], 'getData').and.callThrough();
      spyOn(component, 'addFormControls');
      spyOn(console, 'log');
      component['service'].getData().subscribe(response => {
        expect(component['service'].getData).toHaveBeenCalled();
        expect(component.data).toEqual('my data');
        expect(console.log).toHaveBeenCalledWith(response);
        expect(component.addFormControls).toHaveBeenCalled();
      });
    });