【问题标题】:Angular2 tests running before compileComponents variables are set在设置 compileComponents 变量之前运行的 Angular2 测试
【发布时间】:2017-05-01 01:00:15
【问题描述】:

我在 Angular2 文本组件中遇到问题,当我尝试运行测试运行程序时出现以下错误:

Component: Product Component Should ensure component subscribes to service EventEmitter on instantiation
Failed: Cannot read property 'detectChanges' of undefined
TypeError: Cannot read property 'detectChanges' of undefined
Component: Product Component Should check that service getProducts is called when component getProducts is called
Failed: Cannot read property 'getProducts' of undefined
TypeError: Cannot read property 'getProducts' of undefined

这是我的测试模块:

import { ProductService } from "../../../../services/product.service";
import { TestBed, ComponentFixture, async } from "@angular/core/testing";
import { ProductComponent } from "../../../../components/catalog/products/ProductComponent";
import { HttpModule } from "@angular/http";
import { DebugElement, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import { Observable } from "rxjs/Rx";

class MockProductService {
    emitter = Observable.of({});
    constructor() {

    }

    getProducts() {
        return this;
    }
}

let comp:    ProductComponent;
let fixture: ComponentFixture<ProductComponent>;
let de:      DebugElement;
let el:      HTMLElement;

describe('Component: Product Component', () => {
    let mockProductService;

    beforeEach(() => {
        mockProductService = new MockProductService();

        TestBed.configureTestingModule({
            declarations: [
                ProductComponent
            ],
            providers: [
                {
                    provide: ProductService, useValue: mockProductService
                }
            ],
            imports: [
                HttpModule
            ],
            schemas: [CUSTOM_ELEMENTS_SCHEMA]
        })
        .compileComponents()
            .then(() => {
                fixture = TestBed.createComponent(ProductComponent);
                comp = fixture.componentInstance;
            });
    });

    it('Should ensure component subscribes to service EventEmitter on instantiation', () => {
       // TestBed.compileComponents()
            //.then(() => {
                //spyOn(mockProductService, 'emitter').and.returnValue({
                //    subscribe: () => {}
                //});


                fixture.detectChanges();
                fixture.whenStable().then(() => {
                    expect(comp.products).toBe({});
                });
                //expect(mockProductService.emitter).toHaveBeenCalled();
            //});
    });

    it('Should check that service getProducts is called when component getProducts is called', () => {

        //TestBed.compileComponents()
         //   .then(() => {

                spyOn(mockProductService, 'getProducts').and.returnValue({
                    subscribe: () => {}
                });

                comp.getProducts({});
                expect(mockProductService.getProducts).toHaveBeenCalled();
       // });
    });


});

由于被测组件通过类的 templateUrl 属性使用外部模板,我必须使用 TestBed 的 compileComponents 方法来编译此模板以供测试。正如您所看到的,这会在回调中重新定义一个承诺,然后我会定义夹具和组件实例,以便为每个测试做好准备。因为这是在 beforeEach 中,所以每次测试都会这样做。

当我尝试从我的测试中访问夹具和组件实例时,它说它们是未定义的,这使我相信测试是在从 compileComponents 方法返回承诺之前被调用的。我尝试将 TestBed.CompileComponents 移到每个测试规范中,但这也会导致错误。

谁能建议我在这里需要改变什么? 谢谢

【问题讨论】:

    标签: angular testing karma-runner


    【解决方案1】:

    我已经成功使用了以下两种方法。要么使用DoneFn 推迟beforeEach,直到一切都完成:

    beforeEach(done => {
        mockProductService = new MockProductService();
    
        TestBed.configureTestingModule({
            ...
        })
        .compileComponents()
            .then(() => {
                fixture = TestBed.createComponent(ProductComponent);
                comp = fixture.componentInstance;
                done();
            });
    });
    

    或使用async 并将beforeEach 拆分为两部分:

    beforeEach(async(() => {
        mockProductService = new MockProductService();
    
        TestBed.configureTestingModule({
            ...
        })
        .compileComponents();
    }));
    
    beforeEach(() => {
        fixture = TestBed.createComponent(ProductComponent);
        comp = fixture.componentInstance;
    });
    

    【讨论】:

    • fakeAsync 而不是async
    • 这似乎有效,但在我将其更改为此代码后,我收到此错误。似乎 spyOn getProducts 不起作用并返回 subscribe 函数来模拟对象。 : TypeError: this._productService.getProducts(...).subscribe 不是函数
    • @devoncrazylegs 这是一个单独的问题。我会模仿stackoverflow.com/a/39376968/3001761
    猜你喜欢
    • 1970-01-01
    • 2023-04-11
    • 2010-12-03
    • 2018-07-21
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多