Angular 2 Integration Testing (Unit Test Style)

2019-06-20 08:36发布

问题:

Is it possible to test an angular app with its testing framework (primarily designed for unit testing) against a real backend?

Let's say E2E Testing with Protractor is not an option for me, but still i want to do some integration tests within my Unit Test Environment with Karma. I really have trouble finding examples or even a statement if it's possible or not using Jasmine and the testing libs of angular 2.

I know, that this isn't supposed to be best (or even just a good) practice, but that's not the topic here. Everywhere i searched (and i searched a lot) i'll find approaches with MockBackend and the statement "We don't want to hit the real backend...." but nowhere is said if it's possible at all and if yes, how.

I tried several approaches ("normal" vs. async tests), spying on the service methods from within my Component Testbed, calling the Service functions (which return an Observable, after a backend request is fired) directly and trying to continue from within the subscribe function, but my tests don't care. Those parts are always skipped.

Imagine something like this:

fit('should show an error if the email entered is invalid', async(() => {
    let accService: any = fixture.debugElement.injector.get(AccountService);
    let accSpy: jasmine.Spy = spyOn(accService, 'isExistingEmail').and.callThrough();
    let checkEmailSpy: jasmine.Spy = spyOn(comp, 'checkEmail').and.callThrough();

    expect(checkEmailSpy).not.toHaveBeenCalled();
    emailInput.triggerEventHandler('blur', null);
    fixture.detectChanges();
    expect(checkEmailSpy).toHaveBeenCalled();
    expect(comp.emailInvalid).toBe(true);

    ...

    accService.isExistingEmail('abcdefg').subscribe((res) => {
        expect(accSpy).toHaveBeenCalledTimes(7);
    }, (err) => {
        expect(accSpy).toHaveBeenCalledTimes(7);
    });

    accSpy.calls.mostRecent().returnValue.subscribe((res) => {
        expect(accSpy).toHaveBeenCalledTimes(7);
    }, (err) => {
        expect(accSpy).toHaveBeenCalledTimes(7);
    });

    ...

}));

Now in the first part of this test, the blur event will trigger the components checkEmail function, which will call something in my service (which then will ask another service for the actual backend call and return this observable). If the email is wrong, false will be returned to the components function and comp.emailInvalid is set to true).

The toHaveBeenCalled tests in this part actually pass, but the expect(comp.emailInvalid).toBe(true) part doesn't.

When i run the test and open up the debug tab in Karma-Chrome-Launcher i actually see the real requests to the backend with the right response. So the requests are actually done, but i just don't get these responses back to my test.

In the bottom part of this example, i tried to use the service directly to get my response. So i tried to mock the actual program flow to retrieve the backend responses. But in these cases, the expect calls are never fired. However, if i put some console.log statements in the real service i see that they are called two times (from the blur event and from the direct call accService.isExistingEmail).

Any hints how i could handle this would be so much appreciated.

The main reason for this is, that we don't want to setup huge mock files which simulate the backend responses.

Edit:

If there isn't any solution for this and i still don't want to use UI Tests like E2E with protractor, how would i do integration testing?