【问题标题】:How to test code block inside observable subscription for Angular service如何在 Angular 服务的可观察订阅中测试代码块
【发布时间】:2023-03-25 06:29:01
【问题描述】:

我有一个 Angular 服务方法,它使用另一个服务进行 api 调用。在调用成功后和订阅内部,我调用了一些方法,例如notifySucess,发出新值...

我的问题是如何测试订阅中的代码块,例如期望 notifySucess 已被调用。我在订阅里面放了一个断点,但是代码执行并没有停在那里。

对于测试组件,我知道要应用“fixture.detectChanges()”方法。对于服务测试,有没有类似的机制?

resource.service.ts

@Injectable({
  providedIn: 'root',
})
export class ResourceService {
  constructor(
    private http: HttpClient,  
  ) {}

  putData(newData: Data): Observable<Data> {
    return this.http.put<Data>('/api/put-endpoint', newData);
  }
}

store.service.ts

@Injectable({
  providedIn: 'root',
})
export class StoreService {
  constructor(
    private resource: ResourceService,
    private notificationService: NotificationService,
  )

  saveChanges(newData: Data) {
    this.resourceServie.putData(newData).subscribe(() => {
      this.notificationService.notifySuccess('Save changes successfully');
      // do something else
  }
}

store.service.spec.ts

describe('StoreService', () => {
  let storeService: StoreService;
  let resourceService: jasmine.SpyObj<ResourceService>;
  let notificationService: jasmine.SpyObj<NotificationService>;

  notificationService = jasmine.createSpyObj('NotificationService', ['notifySuccess']);
  resourceService = jasmine.createSpyObj('ResourceService', ['putData']);

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: ResourceService, useValue: resourceService },
        {
          provide: NotificationService,
          useValue: notificationService,
        },
      ],
    });
  });


  it('should saveChanges', () => {
    const newData: Data = {foo: bar};
    resourceService.putData.and.returnValue(of(newData));

    storeService.putData(newData);
    expect(resourceService.putData).toHaveBeenCalledWith(newData); // PASS

    expect(notificationService.notifySuccess).toHaveBeenCalledWith(Save changes successfully); // FAIL as the code block inside the subscription does not run
  });
})

【问题讨论】:

    标签: javascript angular unit-testing rxjs observable


    【解决方案1】:

    您的间谍需要返回一些值来触发订阅。 有关间谍的更多高级信息,您可以阅读here 你需要使用:

    const newData: Data = {foo: bar};
    resourceService = spyOn(resourceService,'putData').and.returnValue(newData);
    

    代替:

    resourceService = jasmine.createSpyObj('ResourceService', ['putData']);
    

    你也可以看到类似的帖子-Angular - unit test for a subscribe function in a component


    尝试用这种方式实现store.service.spec.ts:

    describe('StoreService', () => {
      let storeService: StoreService;
      let resourceService: ResourceService;
      let notificationService: NotificationService;
    
    const newData: Data = {foo: bar};
    resourceService = spyOn(resourceService,'putData').and.returnValue(newData);
    resourceService = spyOn(notificationService,'notifySuccess').and.returnValue('Save changes successfully');
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          providers: [],
        });
    
     resourceService= TestBed.inject(ResourceService);
     notificationService= TestBed.inject(NotificationService);
     storeService = TestBed.inject(storeService);
      });
    
      it('should saveChanges', () => {
    storeService.saveChanges(newData);
    
    expect(resourceService.putData).toHaveBeenCalledWith(newData); 
    expect(notificationService.notifySuccess).toHaveBeenCalledWith(Save changes successfully); /
      });
    })
    

    【讨论】:

    • 间谍已经返回值:resourceService.putData.and.returnValue(of(newData));
    猜你喜欢
    • 2016-06-10
    • 2018-05-07
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 2019-04-08
    相关资源
    最近更新 更多