如何在AngularJSunit testing中模拟$ window.location.replace?

我有以下服务:

angular.module("services") .factory("whatever", function($window) { return { redirect: function() { $window.location.replace("http://www.whatever.com"); } }; }); 

如何在unit testing中模拟$window对象以防止在运行testing时重新加载页面?

我试过使用

spyOn($window.location, 'replace').andReturn(true);

,但它没有工作(仍然有"Some of your tests did a full page reload!"错误)和

$provide.value('$window', {location: {replace: jasmine.createSpy()}})

,但我得到一个错误( Error: [ng:areq] Argument 'fn' is not a function, got Object )堆栈跟踪指向只有angular度自己的源,所以这是没有多大的帮助…

在铬(没有testing其他浏览器),location.replace只读,所以spyOn无法取代它。

$provide.value应该可以工作。 代码中的某处肯定是错的。

这是一个工作单位testing

 describe('whatever', function() { var $window, whatever; beforeEach(module('services')); beforeEach(function() { $window = {location: { replace: jasmine.createSpy()} }; module(function($provide) { $provide.value('$window', $window); }); inject(function($injector) { whatever = $injector.get('whatever'); }); }); it('replace redirects to http://www.whatever.com', function() { whatever.redirect(); expect($window.location.replace).toHaveBeenCalledWith('http://www.whatever.com'); }); }); 

我正在用一个更简单,但也许不那么优雅的解决scheme。 我正在写$ window.location的包装,然后我可以嘲笑。 把它和你的代码联系起来,我会嘲笑whatever.redirect函数,而不是模仿$ window(我假设你的真实函数更复杂)。

所以我最终会:

 angular.module("services") .factory("whatever", function($window) { return { do_stuff_that_redirects: function() { lots of code; this.redirect("http://www.whatever.com"); maybe_more_code_maybe_not; }, redirect: function(url) { $window.location.replace(url); } }; }); 

然后我可以直接模拟redirect的方法,只要相信那只是一行代码就不会出错。

 spyOn(whatever, 'redirect').andCallFake(function(){}); expect(whatever.redirect).toHaveBeenCalledWith('http:/my.expected/url'); 

这对我的目的是足够的,并让我validation所调用的url。

我会提供另一种可能适合你的方法。 我在unit testing一个控制器“行动”,最终redirect用户(整页加载,但到更大的网站/应用程序的不同页面)面临同样的问题。 为了给出一些上下文,控制器触发一个AJAX请求,如果响应正常,它将通过$ window.location.replace()将用户redirect到不同的页面:

 $http.post('save', data) .success(function(responseData, status, headers, config) { if(responseData.redirect) { $window.location.replace(responseData.redirect); } }) .error(function(responseData, status, headers, config) { console.error("ERROR while trying to create the Event!!"); }); 

这个控制器function的testing导致了相同的“你的一些testing做了整页重新加载! 错误。 所以我把下面的代码添加到controller规范的beforeEach()函数中,来模拟$ window服务:

 mockWindow = { location: { replace: function(url) { console.log('redirecting to: ' + url); } } }; eventCtrl = $controller('EventCtrl', { $scope: scope, $window: mockWindow }); 

当然,这个解决scheme阻止我(干净地)validationreplace函数是否被调用了一个预期的参数,但是我现在并不真正关心这个……希望有帮助。

我想你想要的是使用$位置服务,而不是调用$window.location 。 这里还有一个解释这个function的整个页面: http : //docs.angularjs.org/guide/dev_guide.services.$location 。

使用这个,在testing中使用$ location服务的stubbed版本应该相当简单。

 $location.path('/someNewPath'); 

$ location.replace(); //或者你可以链接这些:$ location.path('/ someNewPath')。replace();