【问题标题】:Initialization of TestBed for Angular with Karma使用 Karma 为 Angular 初始化 TestBed
【发布时间】:2017-04-28 10:12:31
【问题描述】:

我有一个适用于 Angular 应用程序的 Karma 设置。目前我正在测试 2 个不同的服务 PerformanceService 和 DataService,所以我有 2 个文件,performance.service.spec.ts 和 data.service.spec.ts

这两个文件都在初始化 TestBed 并配置一个 MockHttp 以在测试服务时使用。

TestBed.initTestEnvironment(
  BrowserDynamicTestingModule,
  platformBrowserDynamicTesting()
);

function createResponse(body) {
  return Observable.of(
    new Response(new ResponseOptions({ body: JSON.stringify(body) }))
  );
}

class MockHttp {
  get() {
    return createResponse([]);
  }
}

据我所知,这可以做一次,不需要为每个服务都做,所以我创建了一个 src/main.spec.ts 并将该代码移到那里,并将其从服务中删除。

现在我运行测试,但它不起作用,我收到错误 TypeError: Cannot read property 'injector' of null

知道为什么会这样吗? main.spec.ts 是首先执行的,所以如果我没记错的话,一旦我们开始测试服务,就应该初始化 TestBed。

谢谢

【问题讨论】:

    标签: angular karma-runner


    【解决方案1】:

    我们的团队遇到了同样的问题。一种解决方案是将 TestBed 初始化提取到一个单独的文件中并对其进行保护,以便它只被初始化一次:

    import { TestBed } from "@angular/core/testing";
    import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing";
    
    export class TestBedInitializer {
    
        static isInitialized: Boolean = false;
    
        static getTestBed() {
            if(!this.isInitialized) {
                TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
                this.isInitialized = true;
            }
    
            return TestBed;
        }
    }
    

    然后可以使用 beforeAll 块中的初始化器来获取 TestBed 的实例:

    import { TestBedInitializer } from './init';
    
    describe('YourSystemUnderTest', () => {
    
        let TestBed;
    
        beforeAll(() => {
            TestBed = TestBedInitializer.getTestBed();
        });
    
        beforeEach(() => TestBed.configureTestingModule({
            imports: [...],
            providers: [...]
        }));
    
        ...
    
    });
    

    此解决方案的优势在于您不依赖于以任何特定顺序运行的测试套件。这让您可以单独或一次全部运行您的套件,而无需更改代码。

    【讨论】:

      【解决方案2】:

      只是想补充一下bobbyg603的答案

      对于 jest 用户 - 只需在 setup-jest.js

      中添加以下代码
      import { TestBed } from "@angular/core/testing";
      import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing";
      
      TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
      

      【讨论】:

        【解决方案3】:

        没有必要创建自己的MockHttp 类,因为Angular 已经创建了一个:https://angular.io/docs/ts/latest/api/http/testing/index/MockBackend-class.html

        示例用法如下:

        describe( 'AppleService', () => {
            let appleService: AppleService,
                response: Response;
        
            beforeEach( () => {
                TestBed.configureTestingModule( {
                    providers: [
                        AppleService,
                        { provide: XHRBackend, useClass: MockBackend },
                        { provide: ComponentFixtureAutoDetect, useValue: true }
                    ],
                    imports: [
                        HttpModule
                    ]
                } )
                .compileComponents();
            } );
        
            it( 'getApples() should return mocked results', async(
                inject( [ Http, XHRBackend ], ( http: Http, backend: MockBackend ) => {
                    backend.connections.subscribe( ( connection: MockConnection ) => {
                        expect( connection.request.url.match( /\/apple$/ ) ).not.toBe( null );
                        expect( connection.request.method ).toBe( RequestMethod.Get );
                        connection.mockRespond( response );
                    } );
        
                    let options = new ResponseOptions( { status: 200, body: [ testApple1, testApple2 ] } );
                    response = new Response( options );
        
                    appleService = new AppleService( resourceService, http );
        
                    appleService.getApples().subscribe( apples => {
                        expect( apples ).toEqual( [ testApple1, testApple2 ] );
                    } );
            } ) ) );
        
        } );
        

        TestBed.get() 也可以用来代替 inject() 包装器。

        【讨论】:

        • 有兴趣了解 MockBackend,但您没有回答我关于 TestBed.initTestEnvironment() 的原始问题
        • 您的 main.spec.ts 是否包含在 karma.conf.ts 预处理器属性中?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-25
        • 1970-01-01
        • 2016-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多