spyOn 在 Angular 中无法使用异步管道

spyOn not working with async pipe in Angular

我有一个运行良好的简单组件,看起来像这样:

@Component({
  selector: 'component',
  template: `
    {{userWithAsyncPipe | async | json}} <!-- = null in test -->
    {{userFromOnInit | json}} <!-- working test -->
  `,
})
export class Component implements OnInit {
  constructor(private service: MyService) {
  }

  userWithAsyncPipe = this.service.getUser();
  userFromOnInit;

  ngOnInit() {
    this.service.getUser().subscribe(user => this.userFromOnInit = user);
  }
}

我正在尝试通过模拟 service.getUser() 方法来测试它。所以我写了一个大致如下所示的测试组件:

describe('', () => {

  ...
  let myService;
  beforeEach(() => {
    myService = TestBed.inject(MyService);
  });

  it('', () => {
    spyOn(myService, 'getUser').and.returnValue(of({name: 'Jacob'}));
  });
});

但是我看karma浏览器,只有变量userFromOnInit被解析了。 userWithAsyncPipe 等于 null.

那是什么鬼?

这里有一个例子 ng-mocks

https://codesandbox.io/s/gallant-bas-is5zy?file=/src/test.spec.ts

import { CommonModule } from "@angular/common";
import {
  Component,
  EventEmitter,
  Input,
  NgModule,
  Injectable,
  Output
} from "@angular/core";
import { MockBuilder, MockInstance, MockRender, ngMocks } from "ng-mocks";
import { EMPTY, Observable, of } from "rxjs";

@Injectable()
class MyService {
  getUser(): Observable<any> {
    return EMPTY;
  }
}

@Component({
  selector: "app-target",
  template: `
    {{ userWithAsyncPipeFn() | async | json }}
    {{ userWithAsyncPipe | async | json }}
    {{ userFromOnInit | json }}
  `
})
class TargetComponent {
  userWithAsyncPipeFn = () => this.service.getUser();
  userWithAsyncPipe = this.service.getUser();
  userFromOnInit: any;

  constructor(private service: MyService) {}

  ngOnInit() {
    this.service.getUser().subscribe((user) => (this.userFromOnInit = user));
  }
}

@NgModule({
  imports: [CommonModule],
  declarations: [TargetComponent],
  providers: [MyService]
})
class TargetModule {}
describe("my sandbox", () => {
  beforeEach(() => MockBuilder(TargetComponent, TargetModule));

  it("should do something", () => {
    MockInstance(MyService, "getUser", () => of({ name: "Jacob" }));

    const fixture = MockRender(TargetComponent);
    expect(fixture.nativeElement.innerHTML.match(
      /\{\s*"name":\s*"Jacob"\s*\}/g
    ).length).toEqual(3);
  });
});