Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
598 views
in Technique[技术] by (71.8m points)

angularjs - E2E mock $httpBackend doesn't actually passThrough for me

Although I believe I'm following the instructions here for setting up $httpBackend to pass selected requests to the server, it's not working for me.

Here is a Plunkr with a failing test that shows what I'm doing and explains in comments what seems to be going wrong.

My spelunking suggests that, for some reason, the mock $httpBackend doesn't have an inner copy of the real $httpBackend so that, when it comes time to pass through the XHR request, it passes it to the mock $httpBackend instead. That second call throws an exception because it doesn't know what to do with the request.

Response to dtabuenc

I remember with appreciation your post on midway testing. You identify an important range of integration testing that falls between unit- and E2E-testing. I am standing on that middle ground.

I don't think you are being snarky at all. Your answer is perfect reasonable ... or it would be reasonable if it weren't contradicted by the text of the "API reference / ngMockE2E / $httpBackend". I quote:

This implementation can be used to respond with static or dynamic responses via the when api and its shortcuts (whenGET, whenPOST, etc) and optionally pass through requests to the real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch templates from a webserver) ...

[I]n an end-to-end testing scenario or in a scenario when an application is being developed with the real backend api replaced with a mock, it is often desirable for certain category of requests to bypass the mock and issue a real http request .... To configure the backend with this behavior use the passThrough request handler of when instead of respond.[emphasis mine].

The documentation is silent on the matter of E2E $httpBackend usage within a Jasmine environment. I can't think of a reason to preclude it. If there is such a reason they should state it clearly. Seriously, who reads about a mock component and doesn't anticipate using it in a test environment?

To "pass through requests to the real $httpBackend for specific requests, e.g. to interact with certain remote apis" is precisely what I intend to do. What could they possibly mean by "real $httpBackend" except the non-mock version of that component?

I do not understand your claim that

The ngMocksE2E module is designed to be used on the "server" side of things where the actual angular application is executing.

The word "server" appears exactly 3 times on that page, not once suggesting that any application code would be executed on a "server". I don't know what you mean by the "actual angular application" executing on "the 'server' side of things."

The documentation is perfectly clear that the E2E $httpBackend is not limited to E2E testing. It is also for "a scenario when an application is being developed with the real backend api replaced with a mock".

That's just a half step away from my scenario in which an application is being tested with the real backend api."

In my scenarios, the SUT is calling upon a component which fetches data from a server. My tests exist to verify that this dependent component succeeds in making such requests of the real backend and will retrieve or save data in the expected manner. This is an integration test that cannot be adequately satisfied by mocking the behavior of the backend.

Of course I can test (and do test) with mock XHR responses the component's ability to respond properly to what I predict will be the backend's behavior. That is not the same as validating that the component responds appropriately to the actual backend's behavior ... which might change as the application evolves and depart from the mocked responses in some significant way.

I would consider using your midway tester for this purpose if I understood how to swap it into the SUT's code path. I don't. I think the component making XHR requests is inaccessible to your ngMidwayTester. But I do know how to jam a real XHR helper into the pipeline if I have to.

Here is where I stand at the moment.

Either someone can show how to make $httpBackend pass certain requests through to the server - as the documentation proclaims it can - or I will replace the passThrough implementation myself with a working XHR implementation.

I prefer the first option. If driven to the second, I shall offer a link to it here for the benefit of others who share my needs and my interpretation of the API documentation.

Is there a 3rd way I'm missing?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I stumbled on the same problem but instead of implementing a rich API or replacing the original angular-mocks simply added in the following helper:

angular.module('httpReal', ['ng'])
    .config(['$provide', function($provide) {
        $provide.decorator('$httpBackend', function() {
            return angular.injector(['ng']).get('$httpBackend');
        });
    }])
    .service('httpReal', ['$rootScope', function($rootScope) {
        this.submit = function() {
            $rootScope.$digest();
        };
    }]);

It patches two issues that prevent an HTTP request from getting passed through:

  1. Restores original $httpBackend;

  2. Provides a method to fulfill the requests, as otherwise they would be in AngularJS' queue waiting for a digest loop.

describe('my service', function() {
    var myService, httpReal;

    beforeEach(module('myModule', 'httpReal'));

    beforeEach(inject(function( _myService_, _httpReal_ ) {
        myService = _myService_;
        httpReal = _httpReal_;
    }));

    it('should return valid data', function(done) {
        myService.remoteCall().then(
            function(data) {
                expect(data).toBeDefined();
                done();
            }, function(error) {
                expect(false).toBeTruthy();
                done();
            });

        httpReal.submit();
    });
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...