单元测试AngularJS $窗口服务

时间:2014-02-08 11:48:17

标签: angularjs

我想对以下AngularJs服务进行单元测试:

.factory('httpResponseInterceptor', ['$q', '$location', '$window', 'CONTEXT_PATH', function($q, $location, $window, contextPath){
     return {
         response : function (response) {
             //Will only be called for HTTP up to 300
             return response;
         },
         responseError: function (rejection) {
             if(rejection.status === 405 || rejection.status === 401) {
                 $window.location.href = contextPath + '/signin';
             }
             return $q.reject(rejection);
         }
     };
}]);

我尝试使用以下套件:

describe('Controllers', function () {
    var $scope, ctrl;
    beforeEach(module('curriculumModule'));
    beforeEach(module('curriculumControllerModule'));
    beforeEach(module('curriculumServiceModule'));
    beforeEach(module(function($provide) {
       $provide.constant('CONTEXT_PATH', 'bignibou'); // override contextPath here
    }));
    describe('CreateCurriculumCtrl', function () {
        var mockBackend, location, _window;
        beforeEach(inject(function ($rootScope, $controller, $httpBackend, $location, $window) {
            mockBackend = $httpBackend;
            location = $location;
            _window = $window;
            $scope = $rootScope.$new();
            ctrl = $controller('CreateCurriculumCtrl', {
                $scope: $scope
            });
        }));

        it('should redirect to /signin if 401 or 405', function () {
            mockBackend.whenGET('bignibou/utils/findLanguagesByLanguageStartingWith.json?language=fran').respond([{"description":"Français","id":46,"version":0}]);
            mockBackend.whenPOST('bignibou/curriculum/new').respond(function(method, url, data, headers){
                return [401];
            });
            $scope.saveCurriculum();
            mockBackend.flush();
            expect(_window.location.href).toEqual("/bignibou/signin");
        });


    });
});

但是,它失败并显示以下错误消息:

PhantomJS 1.9.2 (Linux) Controllers CreateCurriculumCtrl should redirect to /signin if 401 or 405 FAILED
    Expected 'http://localhost:9876/context.html' to equal '/bignibou/signin'.
PhantomJS 1.9.2 (Linux) ERROR
    Some of your tests did a full page reload!

我不确定出了什么问题以及原因。有人可以帮忙吗?

我只想确保$window.location.href等于 '/bignibou/signin'

编辑1

我设法按照以下方式开始工作(感谢“dskh”):

 beforeEach(module('config', function($provide){
      $provide.value('$window', {location:{href:'dummy'}});
 }));

3 个答案:

答案 0 :(得分:17)

在模块中加载时,可以注入存根依赖项:

angular.mock.module('curriculumModule', function($provide){
            $provide.value('$window', {location:{href:'dummy'}});
        });

答案 1 :(得分:2)

为了让这个对我有用,我不得不做一个小调整。它会出错并说:

navigator.userAgent

所以我添加了$provide.value('$window', { location:{ href:'dummy' }, navigator:{ userAgent:{} } }); 对象让它为我工作。

public static List<Tweet> getTweets(String username, String since, String until, String querySearch) {
    List<Tweet> results = new ArrayList<Tweet>();

    try {
        String refreshCursor = null;
        while (true) {

            String response = getURLResponse(username, since, until, querySearch, refreshCursor);
            System.out.println(response);
            JSONObject json = new JSONObject(response);
            refreshCursor = json.getString("min_position");
            Document doc = Jsoup.parse((String) json.get("items_html"));
            Elements tweets = doc.select("div.js-stream-tweet");

            if (tweets.size() == 0) {
                break;
            }

            for (Element tweet : tweets) {
                String usernameTweet = tweet.select("span.username.js-action-profile-name b").text();
                String txt = tweet.select("p.js-tweet-text").text().replaceAll("[^\\u0000-\\uFFFF]", "");
                int retweets = Integer.valueOf(tweet.select("span.ProfileTweet-action--retweet span.ProfileTweet-actionCount").attr("data-tweet-stat-count").replaceAll(",", ""));
                int favorites = Integer.valueOf(tweet.select("span.ProfileTweet-action--favorite span.ProfileTweet-actionCount").attr("data-tweet-stat-count").replaceAll(",", ""));
                long dateMs = Long.valueOf(tweet.select("small.time span.js-short-timestamp").attr("data-time-ms"));
                Date date = new Date(dateMs);

                Tweet t = new Tweet(usernameTweet, txt, date, retweets, favorites);
                results.add(t);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }       
    return results;
}

答案 2 :(得分:2)

我遇到了同样的问题,并在我的解决方案中更进了一步。我不只是想要一个模拟,我想用Jasmine间谍取代$window.location.href,以便更好地跟踪对其所做的更改。所以,我从apsiller's example for spying on getters/setters学习,在创建了我的模拟后,我能够监视我想要的属性。

首先,这是一个套件,显示我如何模拟$window,并通过测试来证明间谍按预期工作:

describe("The Thing", function() {
    var $window;

    beforeEach(function() {
        module("app", function ($provide) {
            $provide.value("$window", {
                //this creates a copy that we can edit later
                location: angular.extend({}, window.location)
            });
        });

        inject(function (_$window_) {
            $window = _$window_;
        });
    });

    it("should track calls to $window.location.href", function() {
        var hrefSpy = spyOnProperty($window.location, 'href', 'set');

        console.log($window.location.href);
        $window.location.href = "https://www.google.com/";
        console.log($window.location.href);

        expect(hrefSpy).toHaveBeenCalled();
        expect(hrefSpy).toHaveBeenCalledWith("https://www.google.com/");
    });
});

如上所示,通过调用以下函数生成间谍:(它适用于getset

function spyOnProperty(obj, propertyName, accessType) {
    var desc = Object.getOwnPropertyDescriptor(obj, propertyName);

    if (desc.hasOwnProperty("value")) {
        //property is a value, not a getter/setter - convert it
        var value = desc.value;

        desc = {
            get: function() { return value; },
            set: function(input) { value = input; }
        }
    }

    var spy = jasmine.createSpy(propertyName, desc[accessType]).and.callThrough();

    desc[accessType] = spy;
    Object.defineProperty(obj, propertyName, desc);

    return spy;
}

最后,here's a fiddle demonstrating this in action。我已经针对Angular 1.4和Jasmine 2.3和2.4进行了测试。

相关问题