Destroying App component after running tests

2019-08-11 18:16发布

问题:

i am developing a angular website and i have a problem while running unit tests. I have my app component like this

export class Appcomponent {
    constructor(private service: SomeService) {
        service.init()
    }
}

and the init() method of the service has

init() {
    setInterval(() => {
        this.http.get(' /api/configuration/v1/log').map(res=> res).subscribe(() => {});
    }, 30000)
}

Now the problem is that , when i run unit tests like this,

describe('Appapponent', () => {
  let fixture: ComponentFixture<AppComponent>;
  let app: AppComponent;

  beforeEach(() => {
    TestBed.configureTestingModule(
      {
        declarations: APP_DECLARATIONS,
        imports: APP_IMPORTS,
        providers: [APP_PROVIDERS, { provide: APP_BASE_HREF, useValue: '/' }]
      }
    ).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
    app = fixture.debugElement.componentInstance;
    fixture.detectChanges();
  });

  it('should create the app', () => {
    expect(app).toBeDefined();
  });
});

When i run the tests, tests run properly but the http call keeps on going because of set interval and the tests won't exit. as shown below

Because of this the build gets timeout and fails. How to resolve this issue ? Please help me.

Edit

COnfivguration added

module.exports = function(config) {
    config.set({
        basePath: '',
        frameworks: ['jasmine', '@angular/cli'],
        plugins: [
            require('karma-jasmine'),
            require('karma-phantomjs-launcher'),
            require('karma-chrome-launcher'),
            require('karma-junit-reporter'),
            require('karma-jasmine-html-reporter'),
            require('karma-coverage-istanbul-reporter'),
            require('@angular/cli/plugins/karma')
        ],
        client: {
            clearContext: false
        },
        files: [
            { pattern: './src/test.ts', watched: false }
        ],
        preprocessors: {
            './src/test.ts': ['@angular/cli']
        },
        coverageIstanbulReporter: {
            reports: ['html', 'lcovonly'],
            fixWebpackSourcePaths: true
        },
        angularCli: {
            environment: 'dev'
        },
        mime: {
            'text/x-typescript': ['ts']
        },
        reporters: ['progress', 'kjhtml'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        mime: { 'text/x-typescript': ['ts', 'tsx'] },
        browsers: ['PhantomJS'],
        singleRun: false,
        captureTimeout: 200000,
        browserDisconnectTimeout: 2000,
        browserDisconnectTolerance: 3,
        browserNoActivityTimeout: 200000
    });
};

回答1:

What I Want to Know

 this.http.get(' /api/configuration/v1/log').map(res=> res).subscribe(() => {});

Why are you using that code and what is the use of it. I think that code is doing nothing. Please make sure this code is really want to your application???.


Problem

But anyway come to the point. Why are you using $http service call inside the controller.component? It should be written in inside of service.componenet section. because then only you can write mock service instead of real service while unit testing.

So, What you want to do in UI unit Testing

You should move this $http call into a service class, like

export class SomeService{
    constructor(private http: $http) {

    }    
   get()
    {
      setInterval(() => {
      this.http.get(' /api/configuration/v1/log').map(res=> 
      res).subscribe(() => {});
    }, 30000)
  }
}
  • Then you should write this same get() method with returning mock data in a Mock Service class.

like,

    export class MockSomeService{
    constructor(private http: $http) {            
    }    
    get()
    {
     return Observable.of({});   //{} send mock data which you want to be check          
    }
 }
  • And pass that mock class instead of real class via providers while configuring your test component.

like,

providers: [{ provide: SomeService, useClass: MockSomeService}]

Now the real service has been mocked while testing. So you can get the mock data instead of real data/real service call to check the test case expectation.


Solution for SetTimout() issue

Normally if you are using Settimeout() function in your controller.componenet. You need to add this below line of code next to the fixture.detectChanges(); in test cases.

        tick(3000);
        fixture.whenStable().then(() => {
            expect(0).toEqual(0);// do your expectation 
        });