重复的,但我在这里看了很多其他问题,他们通常会以某种方式错过我正在寻找的东西。他们主要谈论他们自己创建的服务。我可以做,也已经做到了。我试图用我的模拟覆盖角度注入的内容。我以为它会是一样的,但由于某种原因,当我逐步完成代码时,它总是角度$cookieStore而不是我的模拟。
我对茉莉花和angularjs的经验非常有限。我来自C#背景。我通常编写单元测试 moq(C# 的模拟框架)。我习惯看到这样的东西
[TestClass]
public PageControllerTests
{
private Mock<ICookieStore> mockCookieStore;
private PageController controller;
[TestInitialize]
public void SetUp()
{
mockCookieStore = new Mock<ICookieStore>();
controller = new PageController(mockCookieStore.Object);
}
[TestMethod]
public void GetsCarsFromCookieStore()
{
// Arrange
mockCookieStore.Setup(cs => cs.Get("cars"))
.Return(0);
// Act
controller.SomeMethod();
// Assert
mockCookieStore.VerifyAll();
}
}
我想模拟我在其中一个控制器中使用的$cookieStore服务。
app.controller('PageController', ['$scope', '$cookieStore', function($scope, $cookieStore) {
$scope.cars = $cookieStore.get('cars');
if($scope.cars == 0) {
// Do other logic here
.
}
$scope.foo = function() {
.
.
}
}]);
我想确保使用"车库"参数调用 $cookieStore.get 方法。我也希望能够控制它回馈的东西。我希望它返回 0,然后我的控制器必须执行其他一些逻辑。
这是我的测试。
describe('Controller: PageController', function () {
var controller,
scope,
cookieStoreSpy;
beforeEach(function () {
cookieStoreSpy = jasmine.createSpyObj('CookieStore', ['get']);
cookieStoreSpy.get.andReturn(function(key) {
switch (key) {
case 'cars':
return 0;
case 'bikes':
return 1;
case 'garage':
return { cars: 0, bikes: 1 };
}
});
module(function($provide) {
$provide.value('$cookieStore', cookieStoreSpy);
});
module('App');
});
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller;
}));
it('Gets car from cookie', function () {
controller('PageController', { $scope: scope });
expect(cookieStoreSpy.get).toHaveBeenCalledWith('cars');
});
});
这是我们在之前的回答中讨论的解决方案。
在我的控制器中,我正在使用$location.path和$location.search。因此,为了用我的模拟覆盖$location,我做到了:
locationMock = jasmine.createSpyObj('location', ['path', 'search']);
locationMock.location = "";
locationMock.path.andCallFake(function(path) {
console.log("### Using location set");
if (typeof path != "undefined") {
console.log("### Setting location: " + path);
this.location = path;
}
return this.location;
});
locationMock.search.andCallFake(function(query) {
console.log("### Using location search mock");
if (typeof query != "undefined") {
console.log("### Setting search location: " + JSON.stringify(query));
this.location = JSON.stringify(query);
}
return this.location;
});
module(function($provide) {
$provide.value('$location', locationMock);
});
我不必在$controller中注入任何东西。它只是奏效了。查看日志:
日志:"### 使用位置集"
日志:"### 设置位置:/test"
日志:"### 使用位置搜索模拟"
日志:"### 设置搜索位置:{"限制":"50","q":"ani","tags":[1,2],"category_id":5}'
如果要检查参数,请监视方法
// declare the cookieStoreMock globally
var cookieStoreMock;
beforeEach(function() {
cookieStoreMock = {};
cookieStoreMock.get = jasmine.createSpy("cookieStore.get() spy").andCallFake(function(key) {
switch (key) {
case 'cars':
return 0;
case 'bikes':
return 1;
case 'garage':
return {
cars: 0,
bikes: 1
};
}
});
module(function($provide) {
$provide.value('cookieStore', cookieStoreMock);
});
});
然后测试参数
expect(searchServiceMock.search).toHaveBeenCalledWith('cars');
这是一个示例 https://github.com/lucassus/angular-seed/blob/81d820d06e1d00d3bae34b456c0655baa79e51f2/test/unit/controllers/products/index_ctrl_spec.coffee#L3 它是带有 mocha + sinon 的 coffeescript 代码.js但想法是一样的。
基本上,使用以下代码片段,您可以加载模块并替换其服务:
beforeEach(module("myModule", function($provide) {
var stub = xxx; //... create a stub here
$provide.value("myService", stub);
}));
稍后在规范中,您可以注入此存根服务并执行断言:
it("does something magical", inject(function(myService) {
subject.foo();
expect(myService).toHaveBeenCalledWith("bar");
}));
有关模拟和测试的更多详细信息和提示,您可以在这篇出色的博客文章中找到:http://www.yearofmoo.com/2013/09/advanced-testing-and-debugging-in-angularjs.html
当您可以直接使用它而无需修改时,为什么要模拟 cookieStore?下面的代码是控制器的部分单元测试,该控制器使用$cookieStore来放置和获取cookie。如果您的控制器有一个名为"setACookie"的方法,该方法使用 $cookieStore.put('cookieName', cookieValue) ...然后测试应该能够读取设置的值。
describe('My controller', function() {
var $cookieStore;
describe('MySpecificController', function() {
beforeEach(inject(function(_$httpBackend_, $controller, _$cookieStore_) {
$cookieStore = _$cookieStore_;
// [...] unrelated to cookieStore
}));
it('should be able to reference cookies now', function () {
scope.setACookie();
expect($cookieStore.get('myCookieName')).toBe('setToSomething');
});
});