【问题标题】:How to write a jasmine test case for a function which is called inside ngOnInit?如何为在 ngOnInit 中调用的函数编写 jasmine 测试用例?
【发布时间】:2021-10-15 05:38:11
【问题描述】:

我正在努力为以下代码编写一个成功的测试用例。

在component.ts中

id = 123456;
data = [];
constructor(private serv: ApiService){}

ngOnInint(){
    getData(id);
}

getData(id){
   this.serv.getRequest(url+id).subscribe({
   (res){
        this.data = res;
   });
}

在 spec.ts 文件中

describe('component', () =>{
    let component: DataComponent,
    let fixture: ComponentFixture<OpenCasesComponent>;
    let serv: ApiService;

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports:[HttpClientTestingModule],
            declartions:[DataComponent],
            Providers: [ApiService]
        })
        .compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.CreateComponent(DataComponent);
        component = fixture.componentInstance;
        apiService = TestBed.inject(ApiService);
        fixture.detectChanges();
    });

    it('should make api call on load', fakeAsync(()=>{
        component.id = '123456';
        let fakeResponse = {
            name: 'John';
        }
        component.ngOnInit();
        fixture.detectChanges();
        
        spyOn(component, 'getData').withArgs('123456').and.callThrough();
        spyOn(apiService, 'getRequest')..and.returnValue(of(fakeResponse));
        fixture.detectChanges();
        tick();
        expect(component.getData).toHaveBeenCalled();
        expect(apiService.getRequest).toHaveBeenCalled();
        expect(component.data).toContain(fakeResponse);
    }));
}

类似的函数调用适用于类似的代码。不同之处在于,该功能是由单击按钮触发的。我的猜测是我这里没有调用函数,如果是我该怎么做。

我做错了什么?

【问题讨论】:

    标签: javascript angular typescript jasmine karma-jasmine


    【解决方案1】:

    您应该意识到的主要事情是,您调用的第一个fixture.detectChanges() 是在调用ngOnInit 时。

    我会帮助你的,尽量关注cmets:

    import { of } from 'rxjs';
    .....
    describe('component', () =>{
        let component: DataComponent,
        let fixture: ComponentFixture<OpenCasesComponent>;
        // change the type of this line to be a spyObj
        let serv: jasmine.SpyObj<ApiService>;
    
        beforeEach(async () => {
            // create a spy object where we will mock ApiService
            // the first string argument is an identifier in case of errors
            // and the 2nd array of strings are public methods that you would like to mock
            serv = jasmine.createSpyObj<ApiService>('ApiService', ['getRequest']);
            await TestBed.configureTestingModule({
                // Pretty sure you don't need HttpClientTestingModule now
                // imports:[HttpClientTestingModule],
                // declarations is spelt wrong here
                declarations:[DataComponent],
                // lowercase p for providers here
                // when the component requires ApiService, give it the value
                // of this mock we just created
                providers: [{ provide: ApiService, useValue: serv }],
            })
            .compileComponents();
        });
    
        beforeEach(() => {
            fixture = TestBed.CreateComponent(DataComponent);
            component = fixture.componentInstance;
            apiService = TestBed.inject(ApiService);
            // this first fixture.detectChanges() we call is when ngOnInit is called
            // so let's make sure the API call will work before it is called
            // by providing fake data
            serve.getRequest.and.returnValue(of({ name: 'John' }));
            fixture.detectChanges();
        });
    
        it('should make api call on load', fakeAsync(()=>{
            component.id = '123456';
            let fakeResponse = {
                name: 'John';
            }
            // spy before calling ngOnInit
            spyOn(component, 'getData').and.callThrough();
            
            component.ngOnInit();
            fixture.detectChanges();
           
            expect(component.getData).toHaveBeenCalled();
            expect(serv.getRequest).toHaveBeenCalled();
            expect(component.data).toContain(fakeResponse);
        }));
    }
    

    如果您不想进行所有这些更改,那么以下更改也应该足够了:

    it('should make api call on load', fakeAsync(()=>{
            component.id = '123456';
            let fakeResponse = {
                name: 'John';
            }
            // set your spies before calling ngOnInit !!
            // try removing the withArgs here
            spyOn(component, 'getData').and.callThrough();
            spyOn(apiService, 'getRequest').and.returnValue(of(fakeResponse));
            component.ngOnInit();
            fixture.detectChanges();
            
            fixture.detectChanges();
            tick();
            expect(component.getData).toHaveBeenCalled();
            expect(apiService.getRequest).toHaveBeenCalled();
            expect(component.data).toContain(fakeResponse);
        }));
    

    【讨论】:

    • 您好,感谢您的帮助。现在getData(id) 被调用,但服务没有被调用。 expect(apiService.getRequest).toHaveBeenCalled(); expect(component.data).toContain(fakeResponse); 失败了。我尝试了您的两种解决方案。请帮忙。
    • 在调用服务时,我正在像这样存储订阅。 this.subscription =this.serv.getRequest(url+id).subscribe({(res){this.data = res;}); 会不会有影响?
    • 我认为this.subscription 不会影响它。尝试删除.withArgs。这真的很奇怪,如果它调用getData,那么getRequest也应该被调用。
    • 如果有帮助,我在其他组件中调用相同的服务,也只有 getData() 方法被调用,服务没有被调用。
    • 感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 2021-07-11
    • 2018-11-04
    • 2019-04-13
    • 2017-05-29
    相关资源
    最近更新 更多