带有$ http请求的AngularJS单元测试从不触发.then()回调 [英] AngularJS unit test with $http request never fires .then() callbacks

查看:107
本文介绍了带有$ http请求的AngularJS单元测试从不触发.then()回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在单独的json文件中以模拟响应运行单元测试.当我使用$ q返回在OpsService中手动解析的promise时,这些测试正在工作,但是当我尝试将它们变成实际的$ http请求以返回实际的json文件时,它们不再起作用.

I'm trying to get unit tests running with mocked responses in separate json files. The tests were working when I used $q to return promises resolved manually in my OpsService, but when I tried to make them into actual $http requests to return the actual json files, they no longer worked.

我已经尝试过$httpBackend.flush()$rootScope.$apply()$rootScope.$digest(),但是似乎没有一个能解决诺言.

edit: I've tried $httpBackend.flush(), $rootScope.$apply(), and $rootScope.$digest() but none of those seem to resolve the promises.

我的服务:

OpsService.service('OpsService', function ($q, $http) {

    this.get = {
        bigTen : function () {
            // var defer = $q.defer();
            // defer.resolve({"data":{"alltime":125077,"record":{"date":"2016-07-19","count":825},"today":281}});
            // return defer.promise;

            return $http({
                method: 'GET',
                url: '/jsonMocks/api/big-ten.json'
            }).then(function (response) {
                console.log('bigTen data');
                console.log(response);
                return response;
            }, function (error) {
                console.log('ERROR');
                console.log(error);
            });
        },

        dashboardData : function () {
            console.log('blahhhhh');
            return $http({
                method: 'GET',
                url: '/jsonMocks/api/dashboard-data.json'
            }).then(function (response) {
                console.log('dasbhoard data');
                console.log(response);
                return response;
            }, function (error) {
                console.log('ERROR');
                console.log(error);
            });
        }
    };

    return this;
});

我的控制器:

homeModule.controller('HomeController', function ($scope, OpsService) {
    var ctrl = this;
    ctrl.loading = {
        topMetrics: true,
        dashboardData: true
    };

    function init() {
        ctrl.topMetricData();

        ctrl.getDashboardData();

        ctrl.initialized = true;
    }

    ctrl.topMetricData = function () {
        ctrl.loading.topMetrics = true;
        console.log('in topMetricData()');
        return OpsService.get.bigTen().then(function (bigTen) {
            console.log('bigTenControllerCallback');

            ctrl.loading.topMetrics = false;
            return bigTen;
        });
    };

    ctrl.getDashboardData = function () {
        ctrl.loading.dashboardData = true;
        console.log('in getDashboardData()');
        return OpsService.get.dashboardData().then(function (response) {
            console.log('getDashboardDataController Callback');

            ctrl.loading.dashboardData = false;
            return dashboardData;
        });
    };

    init();
});

我的测试:

describe('home section', function () {
    beforeEach(module('ngMockE2E'));
    beforeEach(module('templates-app'));
    beforeEach(module('templates-common'));
    beforeEach(module('LROps.home'));

    var $rootScope, $scope, $httpBackend, createController, requestHandler;

    beforeEach(inject(function($injector, _$rootScope_, _$controller_, _OpsService_) {
        $rootScope = _$rootScope_;

        $httpBackend = $injector.get('$httpBackend');

        var bigTenJson = readJSON('jsonMocks/api/big-ten.json');
        console.log(bigTenJson);
        $httpBackend.when('GET', '/jsonMocks/api/big-ten.json')
            .respond(200, { data: bigTenJson });
        // .respond(200, { data: 'test1' });

        var dashboardDataJson = readJSON('jsonMocks/api/dashboard-data.json');
        console.log(dashboardDataJson);
        $httpBackend.when('GET', '/jsonMocks/api/dashboard-data.json')
            .respond(200, { data: dashboardDataJson });
        // .respond(200, { data: 'test2' });

        var $controller = _$controller_;
        createController = function() {
            $scope = $rootScope.$new();
            return $controller('HomeController', {
                $scope : $scope,
                OpsService : _OpsService_
            });
        };
    }));

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should retrieve big ten data', inject(function () {
        $httpBackend.expect('GET', '/jsonMocks/api/big-ten.json');
        $httpBackend.expect('GET', '/jsonMocks/api/dashboard-data.json');

        // Controller Setup
        var ctrl = createController();

        // Initialize
        $rootScope.$apply();
        $rootScope.$digest();

        expect(ctrl.topMetrics.display.messages.count).toEqual(745);
    }));

});

因此,我的console.log()均未在.then()回调中触发.如果我改回返回$q.defer().resolve(response).promise对象,它似乎可以正常工作.

So, none of my console.log() are firing in the .then() callbacks. If I change back to returning a $q.defer().resolve(response).promise object, it seems to work fine.

注意:我正在使用karma-read-json读取JSON文件并在测试中做出相应的响应.据我所知,它们已经被正确读取,只是承诺没有得到解决,因此.then()回调可以执行.

Note: I'm using karma-read-json to read the JSON files and respond accordingly in my tests. As far as I can tell, they're being read properly, it's just the promises aren't being resolved so the .then() callbacks can execute.

推荐答案

第一件事是,每个断言的请求都应为模拟请求.请求应使用$httpBackend.flush()刷新,它会触发摘要,不应调用$rootScope.$apply()$rootScope.$digest()(它们彼此重复).

The first thing is that each asserted request should be mocked request. The requests should be flushed with $httpBackend.flush(), it triggers a digest, $rootScope.$apply() and $rootScope.$digest() (they duplicate each other) shouldn't be called.

第二件事是,它不应该在控制器规格中完成!控制器是一个依赖于服务的独立单元,应与模拟服务隔离对其进行测试. OpsService是另一个单位.

The second thing is that it shouldn't be done in controller spec! Controller is a separate unit that depends on a service, it should be tested in isolation with mocked service. OpsService is a different unit.

it('should retrieve big ten data', inject(function () {
    $httpBackend.expect('GET', '/jsonMocks/api/big-ten.json').respond(200, ...);
    $httpBackend.expect('GET', '/jsonMocks/api/dashboard-data.json').respond(200, ...);

    OpsService.get.bigTen().then(function (result) {
       expect(result)...
    }, function (err) {
       throw err;
    });
    OpsService.get.dashboardData()...

    $httpBackend.flush();
}));

it('should test a controller', inject(function () {
    var OpsServiceMock = { get: {
       bigTen: jasmine.createSpy().and.returnValue(...),
       dashboardData: jasmine.createSpy().and.returnValue(...)
    } };

    $scope = $rootScope.$new();

    var ctrl = $controller('HomeController', {
        $scope : $scope,
        OpsService : OpsServiceMock 
    });

    $rootScope.$digest();

    expect(OpsServiceMock.get.bigTen).toHaveBeenCalled();
    expect(OpsServiceMock.get.dashboardData).toHaveBeenCalled();
    expect...
}));

这篇关于带有$ http请求的AngularJS单元测试从不触发.then()回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆