当前位置: 首页 > 知识库问答 >
问题:

Angular中的单元测试:Mocking RxJS可观察到茉莉

厍和颂
2023-03-14

我正在单元测试Angular 12组件。组件在初始化时从服务中获取可观察的返回(参见下面的thing.service.ts)。它被分配给一个主题,该主题通过async管道显示在html模板中(参见下面的app.component.html)。

AppComponent.ts

export class AppComponent  {
  public errorObjectSubject = null;
  public thingsSubject: Subject<Array<IThing>> = new Subject();

  constructor(private readonly _service: ThingService) {
    this._getAllProducts();
  }

  private async _getAllProducts(): Promise<void> {
    this._service.getAllObservableAsync()
      .pipe(take(1),
        catchError(err => {
          this.errorObjectSubject = err;
          return throwError(err);
        })
      ).subscribe(result => { this.thingsSubject.next(result) });
  }
}

模板订阅公共内容主题:主题

app.component.html

<div>
  <app-thing *ngFor="let thing of thingsSubject | async" [thing]="thing"></app-thing>
</div>

thing.service.ts

  constructor(private readonly _http: HttpClient) { }

  public getAllObservableAsync(): Observable<Array<IThing>> {
    return this._http.get<Array<IThing>>('https://jsonplaceholder.typicode.com/todos'); }

这是测试设置。

app.component.spec.ts

describe('AppComponent', () => {
  let component: AppComponent,
    fixture: ComponentFixture<AppComponent>,
    dependencies: { thingService: ThingServiceStub };

  function getThings(): Array<DebugElement> {
    return fixture.debugElement.queryAll(By.directive(ThingComponentStub));
  }

  beforeEach(async () => {
    dependencies = {
      thingService: new ThingServiceStub()
    };
    await TestBed.configureTestingModule({
      declarations: [AppComponent, ThingComponentStub],
      providers: [
        { provide: ThingService, useValue: dependencies.thingService }
      ]
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    //fixture.detectChanges();
  });

  describe('on initialisation', () => {
    let getThingsSubject: Subject<Array<IThing>>;

    beforeEach(() => {
      getThingsSubject = new Subject();
      (dependencies.thingService
        .getAllObservableAsync as jasmine.Spy).and.returnValue(
        getThingsSubject.asObservable()
      );
      fixture.detectChanges();
    });

    it('should fetch all of the things', () => {
      //fixture.detectChanges();
      expect(
        dependencies.thingService.getAllObservableAsync
      ).toHaveBeenCalledWith();
    });

    describe('when the things have been fetched', () => {
      beforeEach(fakeAsync(() => {
        getThingsSubject.next()
        // getThingsSubject.next([
        //   {
        //     userId: 1,
        //     id: 1,
        //     title: 'string',
        //     completed: 'string'
        //   }
        // ]);
        //getThingsSubject.pipe().subscribe()

        tick();

        fixture.detectChanges();
      }));

      it('should display the things', () => {
        expect(getThings()[0].componentInstance.product).toEqual({
          name: 'product',
          number: '1'
        });
      });
    });
  });
});

thing.service.stub.ts

export class ProductServiceStub {
    public getAllObservableAsync: jasmine.Spy = jasmine.createSpy('getAllObservableAsync');
  }

我正在尝试在模板中填充内容(IThing[])之后测试它的工作方式。我有一个合格的规范,称模拟可观察:

it('should fetch all of the things', () => {
  expect(
    dependencies.thingService.getAllObservableAsync
  ).toHaveBeenCalledWith();
});

然而,当我尝试测试模板时,我点击了“Error:Uncaught(in promise):TypeError:cannotreadproperty'pipe'of undefine:descripe('当东西被提取时')。

我不太清楚是什么问题。这是我设置订阅主题的方式吗?还是变化检测?


共有1个答案

夏侯嘉荣
2023-03-14

我认为你称呼事物的顺序可能是个问题。

试试这个:

describe('AppComponent', () => {
  let component: AppComponent,
    fixture: ComponentFixture<AppComponent>,
    dependencies: { thingService: ThingServiceStub };
  

  function getThings(): Array<DebugElement> {
    return fixture.debugElement.queryAll(By.directive(ThingComponentStub));
  }

  beforeEach(async () => {
    dependencies = {
      thingService: new ThingServiceStub()
    };
    await TestBed.configureTestingModule({
      declarations: [AppComponent, ThingComponentStub],
      providers: [
        { provide: ThingService, useValue: dependencies.thingService }
      ]
    }).compileComponents();
  });

  beforeEach(() => {
    // !! This (.createComponent) is when the constructor is called, so mock the observable
    // before here and change the subject to a BehaviorSubject.
    // Maybe subject will work as well.
    let getThingsSubject = new BehaviorSubject([{ name: 'product', number: '1' }]);
    (dependencies.thingService.getAllObservableAsync as jasmine.Spy).and.returnValue(
       getThingsSubject.asObservable()
    );
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

  describe('on initialisation', () => {
    let getThingsSubject: Subject<Array<IThing>>;

    it('should fetch all of the things', () => {
      expect(
        dependencies.thingService.getAllObservableAsync
      ).toHaveBeenCalledWith();
    });

    describe('when the things have been fetched', () => {
      // maybe tick and fakeAsync are not needed but `fixture.detectChanges` is
      beforeEach(fakeAsync(() => {

        tick();

        fixture.detectChanges();
      }));

      it('should display the things', () => {
        // !! Add this log for debugging
        console.log(fixture.nativeElement);
        expect(getThings()[0].componentInstance.product).toEqual({
          name: 'product',
          number: '1'
        });
      });
    });
  });
});
 类似资料:
  • 问题内容: 给定汽车清单(),我可以这样做: 有没有办法我可以从一个到一个序列? 像没有参数的东西 问题答案: 您可以这样映射到: 请注意,flatMapping可能不会保留源可观察的顺序。如果订单对您很重要,请使用。

  • 学习角得到服务和组件和可观察性。 我正在尝试在我的演示应用程序中实现暗模式。该控件由一个服务完成,该服务根据浏览器默认值(如果找到)设置暗主题。 它在应用程序组件中初始化,以便以后在应用程序中放置控制开关。 暗模式从布尔值开始工作,因此为true或false。据我所知,使用一个可观察对象是不够的,因为我希望多个订阅者都以两种方式绑定到订阅,每种方式在服务中切换这些可观察对象。到目前为止,我很肯定这

  • 问题内容: 我一直在阅读Observer模式,以保持UI处于最新状态,但仍然看不到它的用途。即使在我的特定对象中通知了我的MainActivity然后运行update();方法我仍然无法使用Pet对象来获取更新值,因为该对象是在Oncreate中创建的…而我只是无法创建新对象,因为那时变量会有所不同..这是我的实施,它似乎不起作用。 观察者/ MainActivity 可观察/宠物 问题答案: 首

  • 为什么我会得到nullPointerException尽管我删除了observer并使用了mLiveData.getValue()和assertNotNull(mLiveData)它工作得很好? 和错误

  • 我试图理解当我使用 在或之后,在我使用时返回true 我知道是一次性的。isDisposed()返回false。有人能解释一下到底发生了什么吗?。我理解一个写得很好的观察。create不能在onComplete()或onError()之后发出项。

  • 我需要用jasmine对一些DOM操作函数进行单元测试(目前我在浏览器和Karma中运行测试) 我想知道最好的方法是什么? 例如,我可以模拟和存根窗口,记录对象和spyOn的几个函数。但这看起来并不是一个简单的解决方案,所以我要问这个问题! 或者有没有更好的方法(也许不用茉莉花)来做到这一点? 非常感谢