2012-11-16 66 views
2

有以下角度控制器我如何嘲笑的角度服务的功能茉莉花

function IndexCtrl($scope, $http, $cookies) { 

    //get list of resources 
    $http.get(wtm.apiServer + '/v1/developers/me?access_token=' + $cookies['wtmdevsid']). 
    success(function(data, status, headers, config) { 
     // snip 
     }). 
     error(function(data, status, headers, config) { 
     // snip 
     }); 

$scope.modal = function() { 
     // snip 
} 

return; 
} 

我所试图做的是模拟在$ http服务get方法。这里是我的单元测试代码:

describe('A first test suite', function(){ 
    it("A trivial test", function() { 
     expect(true).toBe(true); 
    }); 
}); 

describe('Apps', function(){ 
describe('IndexCtrl', function(){ 
    var scope, ctrl, $httpBackend; 
    var scope, http, cookies = {wtmdevsid:0}; 

    beforeEach(inject(function($injector, $rootScope, $controller, $http) { 
     scope = $rootScope.$new(); 

     ctrl = new $controller('IndexCtrl', {$scope: scope, $http: $http, $cookies: cookies}); 
     spyOn($http, 'get'); 
     spyOn(scope, 'modal'); 

    })); 

    it('should create IndexCtrl', function() { 
     var quux = scope.modal(); 
     expect(scope.modal).toHaveBeenCalled(); 
     expect($http.get).toHaveBeenCalled(); 
    }); 
    }); 
}); 

当我运行此我得到 的ReferenceError:WTM没有定义。

wtm是一个全局对象,当我运行我的测试时,它是不会被定义的,因为当我运行我的测试时,它所声明的代码没有运行。我想知道的是为什么真正的$ http.get函数被调用,我如何设置一个间谍或存根,以便我实际上不调用真正的函数?

(inb4恨在全局:我的同事之一一直负责保理那些了我们的代码:))

回答

4

你需要线了提前测试你的$httpBackendwhenGET方法。尝试在“单元测试与模拟后端”下的测试beforeEach()函数中设置它... There is a good example here

+0

,我想原因是因为我无法预测的时间提前什么网址将被传递给GET()。我想要做一些类似 $ httpBackend.when('GET','*')。respond({}); 但我猜这个*在上下文中不起作用,因为我仍然得到相同的ReferenceError:wtm没有定义。 – akronymn

+0

现在我想到了这一点,不管我告诉GET的期望是什么路径。当它运行我的控制器代码时,它将尝试解析该wtm变量。除非有人嘲笑GET函数,否则它实际上会忽略在代码中传递给它的参数,所以在实际测试此控制器之前,我将不得不重构该全局wtm varibale。 – akronymn

+0

其实它现在看起来像我可以使用你建议的whenGET函数,blesh,现在声明并在我的测试范围内定义wtm。 – akronymn

1

也许你可以在$ httpBackend周围创建一个自定义的包装模拟器来处理你的特殊需求。

详细说明,角度使用最后降临策略策略覆盖同名组件,这意味着您的模块加载顺序在您的测试中很重要。

当您定义另一个具有相同名称的服务并在第一个服务之后加载它时,最后一个服务将被注入而不是第一个服务。例如: -

apptasticMock.service("socket", function($rootScope){ 
    this.events = {}; 

    // Receive Events 
    this.on = function(eventName, callback){ 
    if(!this.events[eventName]) this.events[eventName] = []; 
    this.events[eventName].push(callback); 
    } 

    // Send Events 
    this.emit = function(eventName, data, emitCallback){ 
    if(this.events[eventName]){ 
     angular.forEach(this.events[eventName], function(callback){ 
     $rootScope.$apply(function() { 
      callback(data); 
     }); 
     }); 
    }; 
    if(emitCallback) emitCallback(); 
    } 

}); 

这项服务提供完全相同的接口和行为完全像原来的人,除非它通过任何插座从未进行通信。这是我们想用于测试的服务。

随着角度考虑装载序列,测试然后看起来像这样:

describe("Socket Service", function(){ 
    var socket; 

    beforeEach(function(){ 
    module('apptastic'); 
    module('apptasticMock'); 

    inject(function($injector) { 
     socket = $injector.get('socket'); 
    }); 
    }); 

    it("emits and receives messages", function(){ 
    var testReceived = false; 

    socket.on("test", function(data){ 
     testReceived = true; 
    }); 

    socket.emit("test", { info: "test" }); 
    expect(testReceived).toBe(true); 
    }); 

});

这里重要的是module('apptasticMock')module('apptastic')之后被执行。这将覆盖原始套接字实现与嘲弄的一个。剩下的就是正常的依赖注入过程。

This article I wrote对您而言可能是件有趣的事,因为它会提供更多细节。

4

我建议所有使用你在这里描述的方式的全局变量应该通过$window服务使用。

所有可用的全局变量(如window.wtm)也将在$ window.atm上可用。

然后你就可以完全踩灭你的WTM参考,并窥探它,你已经描述的一样:我得到了同样的问题

var element, $window, $rootScope, $compile; 

    beforeEach(function() { 
    module('fooApp', function($provide) { 
     $provide.decorator('$window', function($delegate) { 

      $delegate.wtm = jasmine.createSpy(); 

      return $delegate; 
     }); 
    }); 

    inject(function(_$rootScope_, _$compile_, _$window_) { 
     $window = _$window_; 
     $rootScope = _$rootScope_; 
     $compile = _$compile_; 
    });  

    }); 
+1

这应该是正确的答案! –