如何在Angular 2最终版本中编写HTTP模拟单元测试?

时间:2016-10-18 12:38:10

标签: unit-testing angular

我已从RC4迁移到最终版本(2.1.0),我正在重构我的单元测试以符合2.1.0语法。除了HTTP模拟之外,这很容易。

我找不到任何关于如何在2.1.0

中模拟HTTP请求的示例

这是一个RC4 HTTP单元测试。我将如何在最终版本2.1.0中重写它?

it('ngOnInit()',
  async(inject([TestComponentBuilder, XHRBackend], (tcb:TestComponentBuilder, mockBackend:MockBackend) => {
  tcb.createAsync(Route1ListComponent).then((fix:ComponentFixture<Route1ListComponent>) => {

    // THIS BLOCK OF CODE I NEED HELP TO RE-WRITE TO 2.1.0
    mockBackend.connections.subscribe(
      (connection:MockConnection) => {
        connection.mockRespond(new Response(
          new ResponseOptions({
              body: persons
            }
          )));
      });

    // THIS BLOCK OF CODE WILL NOT CHANGE
    let instance = fix.componentInstance;
    instance.ngOnInit();
    expect(instance.persons.length).toBe(3);
  });
})));

注意:请不要提供RC代码。感谢

2 个答案:

答案 0 :(得分:4)

您需要做的第一件事是配置TestBed。不再有TestComponentBuilder。使用TestBed,就像从头开始配置@NgModule,仅适用于测试环境。这意味着您将测试中的组件添加到declarations,将所有提供商添加到provider,并将任何导入添加到imports

要为Http提供商配置模拟后端,您只需从Http创建MockBackend

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [ HttpModule ],
    declarations: [ RouteListComponent ],
    providers: [
      MockBackend,
      BaseRequestOptions,
      {
        provide: Http,
        useFactory: (backend: MockBackend, options: BaseRequestOptions) => {
          return new Http(backend, options);
        },
        deps: [ MockBackend, BaseRequestOptions ]
      }
    ]
  })
})

这应该是配置,假设您不需要任何其他我不知道的提供商或进口。

对于测试,您首先要进行async测试,因为您将在测试中进行异步操作。这与RC没有变化,您只需使用async。如果组件使用templateUrl(并且您没有使用Webpack),则需要调用TestBed.compileComponents(),否则无需调用TestBed.createComponent。之后,您可以使用let fixture: ComponentFixture<RouteListComponent>; let component: RouteListComponent; beforeEach(async(() => { TestBed.configureTestingModule({ ... }) .compileComponents().then(() => { fixture = TestBed.createComponent(RouteListComponent); component = fixture.componentInstance; fixture.detectChanges(); }); })); it('...', async(inject([MockBackend], (backend: MockBackend) => { })))

创建组件
@angular/core/testing

以上与测试相关的所有内容都可以从MockBackend导入。您对component.ngOnInit的使用仍然是相同的。

另外请注意,您无需致电fixture.detectChanges()。当你调用{{1}}

时,框架会调用它

另见:

答案 1 :(得分:2)

非常感谢@peeskillet帮助我找到答案..

import {APP_BASE_HREF} from '@angular/common';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {AppModule} from '../../../app.module';
import {persons} from '../../../data/persons';
import {Route1ListComponent} from './route1-list.component';

// HTTP mocking imports
import {BaseRequestOptions, Http, Response, ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';

describe('route1-list.component.ts', () => {

  let fix: ComponentFixture<Route1ListComponent>;
  let instance: Route1ListComponent;
  let injector: any;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppModule],
      providers: [{provide: APP_BASE_HREF, useValue: '/'},
        MockBackend,
        BaseRequestOptions,
        {
          provide: Http,
          useFactory: (pBackend: MockBackend, pOptions: BaseRequestOptions) => {
            return new Http(pBackend, pOptions);
          },
          deps: [MockBackend, BaseRequestOptions]
        }]
    }).compileComponents()
      .then(() => {
        fix = TestBed.createComponent(Route1ListComponent);
        instance = fix.componentInstance;
        injector = fix.debugElement.injector;
      });
  }));

  it('should instantiate component', () => {
    expect(instance).toEqual(jasmine.any(Route1ListComponent));
  });

  it('should have expected text', () => {
    let el = fix.debugElement.query(By.css('section.route1-list')).nativeElement;
    expect(el.textContent).toMatch(/route 1 list view/i, 'should have expected text');
  });

  it('ngOnInit()', async(() => {
    let backend = injector.get(MockBackend);
    backend.connections.subscribe(
      (connection: MockConnection) => {
        connection.mockRespond(new Response(
          new ResponseOptions({
              body: persons
            }
          )));
      });

    fix.detectChanges(); // Calls instance.ngOnInit()
    expect(instance.persons.length).toBe(3);
  }));

  it('ngOnInit() failure', async(() => {
    let backend = injector.get(MockBackend);
    backend.connections.subscribe(
      (connection: MockConnection) => {
        connection.mockError(new Error('error'));
      });

    fix.detectChanges(); // Calls instance.ngOnInit()
    expect(instance.persons).toBeUndefined();
  }));

});

请注意,在撰写本文时,Angular2文档位于..

https://angular.io/docs/ts/latest/api/http/testing/index/MockBackend-class.html

https://angular.io/docs/ts/latest/api/http/testing/index/MockConnection-class.html

似乎错了。

当我使用文档中详述的Injector.resolveAndCreate时,我收到错误:

  

财产&#39; resolveAndCreate&#39;类型为#in; Injector&#39;。

为了解决这个问题,我必须根据@peeskillet提供的答案来回答