【问题标题】:Angular service testing: Cannot find name 'asyncData'Angular 服务测试:找不到名称“asyncData”
【发布时间】:2018-09-11 19:35:37
【问题描述】:

所以我正在学习如何在 Angular 中测试服务,并尝试在 Angular 文档中复制以下示例。

let httpClientSpy: { get: jasmine.Spy };
let heroService: HeroService;

beforeEach(() => {
  // TODO: spy on other methods too
  httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
  heroService = new HeroService(<any> httpClientSpy);
});

it('should return expected heroes (HttpClient called once)', () => {
  const expectedHeroes: Hero[] =
    [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];

  httpClientSpy.get.and.returnValue(asyncData(expectedHeroes));

  heroService.getHeroes().subscribe(
    heroes => expect(heroes).toEqual(expectedHeroes, 'expected heroes'),
    fail
  );
  expect(httpClientSpy.get.calls.count()).toBe(1, 'one call');
});

我试图照字面意思复制它,但它给了我以下错误:

src/app/services/find-locals.service.spec.ts(17,38) 中的错误:错误 TS2304:找不到名称“asyncData”。

有人可以帮我更换这个吗?或者告诉我我可能在其他地方做错了什么?

这是从 Angular 文档复制的测试文件:

import {FindLocalsService} from './find-locals.service';

import {HttpClient, HttpClientModule} from '@angular/common/http';

let findLocalsService: FindLocalsService;
let httpClientSpy: { get: jasmine.Spy, post: jasmine.Spy };

beforeEach(() => {
  httpClientSpy = jasmine.createSpyObj('HttpClient', ['get', 'post']);
  findLocalsService = new FindLocalsService(<any> httpClientSpy, null);
});

it('should save location to server', function () {
  const expectedData: any =
    [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];

  httpClientSpy.post.and.returnValue(asyncData(expectedData));

  findLocalsService.saveLocation('something').subscribe(
    data => expect(data).toEqual(expectedData),
          fail
  );

  expect(httpClientSpy.post.calls.count()).toBe(1, 'one call');
});

这是服务本身

@Injectable()

export class FindLocalsService {

    constructor(private http: HttpClient, private authService: AuthenticationService){}

    saveLocation(locationObj){
        return this.http.post(url + '/findLocals/saveLocation', locationObj);
    }

    getThreeClosestPlayers() {
        const userId = this.authService.currentUser().user._id;
        console.log('entered 3 closest service', userId);

        return this.http.get(url + '/findLocals/getThreeClosestPlayers/' + userId)
            .pipe(
              map((data: any) => data.obj),
              catchError(this.handleError)
              )
    }
}

【问题讨论】:

    标签: angular testing


    【解决方案1】:

    改变这一行:

    httpClientSpy.get.and.returnValue(asyncData(expectedHeroes));
    

    使用 Observable 运算符of()

    httpClientSpy.get.and.returnValue(of(expectedHeroes));
    

    这将返回一个可以订阅的 observable,并将返回 expectedHeroes。如果你使用的是 Angular 6,你可以直接从 rxjs 导入这个:

    import {of} from 'rxjs';
    

    【讨论】:

    • 阅读教程文档时,他们声称 You can write many useful tests with this spy, even though its Observable is synchronous. 他们稍后包含了这个 asyncData 函数的简介,该函数使用 defer 更加异步,因此即使它可能也不完全相同工作正常。
    • 我想知道为什么 Angolar.io 不将其文章从 asyncData 更改为 Of ???我花了几个小时试图查看我的代码来解决这个问题:|谢谢大佬。
    • 这在方法本身中被记录为错误 * 以下不起作用 * 使用 of().delay() 会触发 TestBed 错误; * 见github.com/angular/angular/issues/10127。 * * 使用asap 调度程序 - 如of(value, asap) - 也不起作用。 github.com/angular/angular/blob/master/aio/content/examples/…
    【解决方案2】:

    我引用自:https://angular.io/guide/testing

    异步 observable 是由 asyncData 助手生成的。 asyncData 助手是一个实用函数,您必须自己编写。或者你可以从示例代码中复制这个:

    测试/async-observable-helpers.ts

    /** Create async observable that emits-once and completes
     *  after a JS engine turn */
    export function asyncData<T>(data: T) {
      return defer(() => Promise.resolve(data));
    }
    

    注意:defer来自rxjs,即:import { defer } from 'rxjs';

    【解决方案3】:

    如果从 Angular 文档下载示例代码,您将在 testing>async-observable-helpers.ts 文件中找到“asyncData”定义。

    【讨论】:

      【解决方案4】:

      Observable.of turn async

      Rx.Observable.of(1, 2, 3, Rx.Scheduler.async).subscribe(
          (val) => console.log(val)
      );
      
      console.log('first');
      This will log out:
      
      //first
      //1
      //2
      //3
      

      但是,默认情况下让of() 同步很好。只需使用 of 即可获得以下订单:

      • 期望1
      • 点击
      • 敲定
      • 期望2

      示例:

      expect1()
      of('hello').pipe(finalize(..),tap(..)).subscribe(..)
      expect2()
      

      如果你改为异步,我想你会得到这个订单:

      • 期望1
      • 期望2
      • 点击
      • 敲定

      当我设计一个服务方法时,我通常让它返回一个 observable,即使组件不需要来自服务的任何数据,我也可能使用 (map(() => null)) 返回 Observable。如果我需要测试该链中的代码,我可以创建一个可以被测试调用的辅助方法。

      【讨论】:

        猜你喜欢
        • 2020-02-15
        • 2017-03-25
        • 2016-12-25
        • 2017-12-30
        • 1970-01-01
        • 2021-03-14
        • 1970-01-01
        • 2016-01-24
        相关资源
        最近更新 更多