【问题标题】:Angular, test, dependency injection, http.get ... Help to understandAngular、测试、依赖注入、http.get……帮助理解
【发布时间】:2017-06-02 18:06:16
【问题描述】:

首先对不起我的英语。

我正在使用 Angular 并通过他的测试开发一个简单的服务。

该服务使用 http.get 方法加载一个 JSON 文件并将其内容存储在一个变量中。 目标并不重要。

在有效的代码下方:

首先是服务

import {Http} from '@angular/http';
import {Injectable} from '@angular/core';
import {Constants} from 'config/constants';
import 'rxjs/Rx';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class LoadJsonFileService {
  private config: Object = null;

  constructor(private http: Http) {
  }

  private loadJsonAndUpdateConfig() {
    this.http
      .get(Constants.CONFIG_FILE_NAME)
      .map(response => response.json())
      .catch((error: any): any => {
        return Observable.throw(error.json().error || 'Server error');
      }).subscribe((configJson) => {
        this.config = configJson;
      });
  }
  public getConfig(key: string): string {
    if (!this.config) {
      this.loadJsonAndUpdateConfig();
    }
    return this.config[key];
  }
}

然后是测试:

import {BaseRequestOptions, ConnectionBackend, Http, RequestOptions, Response, ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';
import {LoadJsonFileService} from './load-json-file.service';
import {inject, TestBed} from '@angular/core/testing';

describe('Test suite ...', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        {provide: RequestOptions, useClass: BaseRequestOptions},
        {provide: ConnectionBackend, useClass: MockBackend},
        Http,
        LoadJsonFileService
      ]
    });
  });

  it('The test ...', inject([ConnectionBackend, LoadJsonFileService],
    (backend,
     service: LoadJsonFileService) => {
      backend.connections.subscribe((c: MockConnection) => {
        c.mockRespond(new Response(new ResponseOptions({body: {key: 'foo'}})));
      });

      expect(service.getConfig('key')).toBe('foo');
    }));

});

测试正常

代码不起作用,我不知道为什么:

import {Http} from '@angular/http';
import {Injectable} from '@angular/core';
import {Constants} from 'config/constants';
import 'rxjs/Rx';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class LoadJsonFileService {
  private config: Object = null;

  constructor(private http: Http) {
    this.loadJsonAndUpdateConfig();
  }

  private loadJsonAndUpdateConfig() {
    this.http
      .get(Constants.CONFIG_FILE_NAME)
      .map(response => response.json())
      .catch((error: any): any => {
        return Observable.throw(error.json().error || 'Server error');
      }).subscribe((configJson) => {
        this.config = configJson;
      });
  }
  public getConfig(key: string): string {
    return this.config[key];
  }
}

不同之处在于 this.loadJsonAndUpdateConfig() 在构造函数中的调用,而不是在 getConfig 方法中。 测试失败:

TypeError: null is not an object (evaluating 'this.config[key]')

当我进行一些调试时,订阅方法永远不会触发,就像 http.get 永远不会调用一样......

我很困惑,有人可以向我解释这种行为吗?

谢谢,

史蒂夫

【问题讨论】:

    标签: angular http dependency-injection jasmine karma-jasmine


    【解决方案1】:

    长话短说,只需为变量分配默认值

    private config: Object = {};
    

    长版本:第一个代码示例也不应该工作,除非你在某处为 config 变量分配了一些东西,或者后端请求在 this.config[key] 块执行之前完成(竞争条件),但如果它在本地(或在测试中)工作),它可能会在服务器上中断。

    基本上,getConfig()this.config = configJson; 之前被调用(我假设在模板中)。 Http 请求是“异步”的,即 js/ts/angular 不会等到它完成,后续代码会在 http 请求发起后立即执行。

    如果您想对其进行测试,请在返回值之前添加异步超时,或者最好查看 InMemoryWebApiModule 上的角度文档

    【讨论】:

    • 谢谢,但问题不是为什么会出现空错误(这是一个后果),我的代码只是为了说明问题:为什么在 loadJsonAndUpdateConfig() 方法被调用时不调用 http.get 方法在构造函数中调用但在我将其放入 getConfig 方法时调用?
    猜你喜欢
    • 1970-01-01
    • 2013-05-23
    • 2018-01-27
    • 2010-10-23
    • 2016-11-09
    • 2020-06-09
    • 1970-01-01
    • 2021-06-19
    相关资源
    最近更新 更多