【问题标题】:How to write an HTTP mock unit test in Angular 2 final release?如何在 Angular 2 最终版本中编写 HTTP 模拟单元测试?
【发布时间】:2016-10-18 12:38:09
【问题描述】:

我已从 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 代码。谢谢

【问题讨论】:

    标签: unit-testing angular


    【解决方案1】:

    您需要做的第一件事是配置TestBed。没有更多的TestComponentBuilder。使用TestBed,就像从头开始配置@NgModule,只是为了测试环境。这意味着您将要测试的组件添加到 declarations,将任何提供程序添加到 provider,并将任何导入添加到 imports

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

    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()时由框架调用

    另请参阅:

    【讨论】:

    • 非常感谢您的回答,如果没有它,我将无法达到本文概述的解决方案。我的解决方案基于此,但无论对错,避免使用 .. async(inject([MockBackend], (backend: MockBackend) .. 这个答案非常感谢......再次感谢:) ...如果您对我的最终解决方案有任何反馈,我们会非常欢迎... +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 时,我收到错误:

    “typeof Injector”类型上不存在属性“resolveAndCreate”。

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

    【讨论】:

      猜你喜欢
      • 2015-08-28
      • 2017-04-13
      • 2017-05-16
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2016-11-23
      • 1970-01-01
      • 2018-11-24
      相关资源
      最近更新 更多