在Angular4中对服务进行单元测试

时间:2017-10-16 10:14:30

标签: angular unit-testing dependency-injection protractor karma-jasmine

我对Angular4的世界相当新,并使用Jasmine / Karama进行测试。我创建了一个包含两个web api服务的小应用程序,我需要为这些服务编写测试。

使用在线示例,以及我对Angular4中模拟的基本理解,我已经设法破解了我的第一个服务及其运行正常的测试。第一个服务的构造函数只有一个依赖项(http模块,恰好与我正在使用的示例一致!)。

服务示例1

// Lookups api wrapper class.
@Injectable()
export class LookupsService {

    private servicegApiUrl = '';

    public constructor( private http : Http ) {  
        // Build the service api url, uring the environment lookups api url, plus controller name to reference.
        this.servicegApiUrl = environment.apiUrl + 'Lookups/';
    }

    // Get the hubs from the web api.
    public getHubs() : Observable<KeyValuePair<number>[]> {
        // Carry out http get and map the result to the KeyValuePair number object.
        return this.http.get(this.servicegApiUrl + 'Hubs').map(res => { 
            if (res){ return res.json() as KeyValuePair<number>[]; }
        });
    }
}

测试示例1 - 测试工作:

describe('Service: LookupService', () => {

  let service: LookupsService;
  let backend: MockBackend;

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

    // Get the MockBackend
    backend = TestBed.get(MockBackend);

    // Returns a service with the MockBackend so we can test with dummy responses
    service = TestBed.get(LookupsService);

  });

  it('getHubs() should return populated KeyValuePair<number>[]', async(() => {
    let response = 
        [{
            "Key": "Hub 1 example",
            "Value": 1
        },{
            "Key": "Hub 2 example",
            "Value": 2
        }]
    ;

    // When the request subscribes for results on a connection, return a fake response
    backend.connections.subscribe(connection => {
      connection.mockRespond(new Response(<ResponseOptions>{
        body: JSON.stringify(response)
      }));
    });

    // Perform a request and make sure we get the response we expect
    var hubsRes : KeyValuePair<number>[];
    service.getHubs().subscribe(hubs => { 
        hubsRes = hubs;
        console.log(hubs);
    });

    // Test hubs is populated.
    expect(hubsRes.length).toBeGreaterThan(0);

  }));

});

到目前为止一切顺利,我现在需要为第二项服务编写测试。在这个服务中,我注入了一个我为日志记录创建的自定义服务(它没有注入任何依赖项,只是包装console.log)。

服务示例2

// Routing Rules api wrapper class.
@Injectable()
export class RoutingRulesService {

    private servicegApiUrl = '';

    public constructor( private loggerService : LoggerService, private http : Http ) {  
        // Build the service api url, uring the environment routing api url, plus controller name to reference.
        this.servicegApiUrl = environment.routingApiUrl + 'routingRules/';
    }

    // Perform search using passed in filter.  Returns SearchResult object.
    public getSearchFiltered(options): Observable<SearchResult> {
        // Api url is the service url, plus Filtered and search query string.
        var apiUrl = this.servicegApiUrl + 'Filtered' + options;
        this.loggerService.logInfo("Route search query url: " + apiUrl);

        // Carry out http get and map the result to the SearchResult object.
        return this.http.get(apiUrl).map(res => { 
            if (res){ return res.json() as SearchResult; }
        });
    }
}

测试示例2 - 测试无法正常工作

describe('Service: RoutingRulesService', () => {

  let service: RoutingRulesService;
  let logger : LoggerService;
  let backend: MockBackend;

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

    // Get the MockBackend
    backend = TestBed.get(MockBackend);

    // Returns a service with the MockBackend so we can test with dummy responses
    service = TestBed.get(RoutingRulesService);

  });

  it('getSearchFiltered(), with no search parameter, should return populated SearchResult', async(() => {
    let response = 
    {
      "Pagination": {
        "RecordCount": 2,
        "PageRecordsFrom": 1,
        "PageRecordsTo": 1,
        "TotalPages": 1,
        "PageSize": 2,
        "PageNumber": 1,
        "SortBy": "RoutingRuleId",
        "Ascending": true
      },
      "Results": [
        {
          "RoutingRuleId": 1,
          "BrandId": 21,
          "CashOnDelivery": false,
          "CreationTime": "2017-09-11T15:14:41.207",
          "CurrencyCode": 2,
          "CurrencyDescription": "USD"
        },
        {
          "RoutingRuleId": 2,
          "BrandId": 21,
          "CashOnDelivery": false,
          "CreationTime": "2017-09-11T15:14:41.207",
          "CurrencyCode": 2,
          "CurrencyDescription": "USD"
        }]
      }    
    ;

    // When the request subscribes for results on a connection, return a fake response
    backend.connections.subscribe(connection => {
      connection.mockRespond(new Response(<ResponseOptions>{
        body: JSON.stringify(response)
      }));
    });

    // Perform a request and make sure we get the response we expect
    var searchRes : SearchResult;
    service.getSearchFiltered(null).subscribe(results => { 
        searchRes = results;
        console.log(results);
    });

    // Test populated.
    expect(searchRes.Pagination.RecordCount).toBeGreaterThan(0);
    expect(searchRes.Results[0].RoutingRuleId).toEqual(1);

  }));
});

编译测试时出现此错误:

服务:RoutingRulesService getSearchFiltered(),没有搜索参数,应返回已填充的SearchResult FAILED         错误:意外的值&#39; LoggerService&#39;由模块&#39; DynamicTestModule&#39;导入。请添加@NgModule注释。

如何成功将新记录器服务实例注入第二个服务?

提前感谢所有提示!

0 个答案:

没有答案