简体   繁体   中英

How to test code block inside observable subscription for Angular service

I have an Angular service method that uses another service for making api call. After the call success and inside of the subscription, I call some methods eg notifySucess, emit new value...

My question is how can I test the code block inside the subscription eg expect notifySucess to have been called. I put a break point inside the subscription, but the code execution does not stop there.

For testing component, I know there is 'fixture.detectChanges()' method to be applied. For service testing, are there any similar mechanism?

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
  });
})

Your spy need to return some value for triggering subscription. More advanced information about spy you can read here You need to use:

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

instead of:

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

You also can see the similar post - Angular - unit test for a subscribe function in a component


Try to implement store.service.spec.ts in this way:

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); /
  });
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM