我目前正在开始使用角度单位测试。作为我想要的第一个控制器看起来像这样,我感到困惑。
angular.module('sgmPaperApp')
.controller('AccountCtrl', function ($mdToast, user, $firebaseArray, Ref) {
var vm = this;
vm.data = user;
vm.save = saveUser;
vm.comments = $firebaseArray(Ref.child('comments').orderByChild('person').equalTo(user.$id));
function saveUser() {
vm.data.$save().then(function () {
$mdToast.showSimple('Data saved');
});
}
});
我真的应该嘲笑我使用的所有外部服务吗?毕竟那个控制器不是很多,那么外部服务和模拟firebaseArray可能很困难。
感谢您的建议并帮助我开始测试
答案 0 :(得分:5)
您不必担心外部依赖项的作用,只需模拟其API。
这是我能看到的唯一嘲笑。我将假设您正在使用Jasmine
var Ref, $firebaseArray, $mdToast, user, vm;
beforeEach(function() {
Ref = jasmine.createSpyObj('Ref', ['child', 'orderByChild', 'equalTo']);
Ref.child.and.returnValue(Ref);
Ref.orderByChild.and.returnValue(Ref);
Ref.equalTo.and.returnValue(Ref);
$firebaseArray = jasmine.createSpy('$firebaseArray').and.returnValue('comments');
$mdToast = jasmine.createSpyObj('$mdToast', ['showSimple']);
user = jasmine.createSpyObj('user', ['$save']);
user.$id = 'id';
module('sgmPaperApp'); // you should consider separate modules per "thing"
inject(function($controller) {
vm = $controller('AccountCtrl', {
$mdToast: $mdToast,
user: user,
$firebaseArray: $firebaseArray,
Ref: Ref
});
});
});
然后您可以轻松创建测试
it('assigns a bunch of stuff on creation', function() {
expect(vm.data).toBe(user);
expect(vm.comments).toEqual('comments'); // that's what the mock returns
expect(Ref.child).toHaveBeenCalledWith('comments');
expect(Ref.orderByChild).toHaveBeenCalledWith('person');
expect(Ref.equalTo).toHaveBeenCalledWith(user.$id);
expect($firebaseArray).toHaveBeenCalledWith(Ref);
});
您甚至可以测试基于承诺的方法,例如saveUser
it('saves the user and makes some toast', inject(function($q, $rootScope) {
user.$save.and.returnValue($q.when()); // an empty, resolved promise
vm.saveUser();
expect(user.$save).toHaveBeenCalled();
expect($mdToast.showSimple).not.toHaveBeenCalled(); // because the promise hasn't resolved yet
$rootScope.$apply(); // resolves promises
expect($mdToast.showSimple).toHaveBeenCalledWith('Data saved');
}));
答案 1 :(得分:1)
因此,要回答这个问题,我们需要考虑我们实际上要做的事情。如果我们尝试单元测试,那么是的,我们需要模拟所有依赖项。
嘲弄你的依赖关系并不难。您只需要模拟您正在使用的内容。
例如,$firebaseArray
作为接收参数的函数开始,我们知道的很多:
var mockFirebaseArray = function(ref) {
};
接下来,在我们完成之前,我们需要模拟Ref
:
var mockRef = {
child: function(path) {
this.orderByChild = function(path) {
this.equalTo = function(val) {
};
return this;
};
return this;
}
};
有了这些东西,我们就可以决定测试将如何通过"。我们可以使用间谍。或者,我们可以设置局部变量,我们可以在以后通过它来断言。
间谍是我的首选方法,因为您甚至可以验证它们是否使用特定值进行调用:
expect(mockFirebaseArray).toHaveBeenCalled();
expect(mockRef.child).toHaveBeenCalledWith('comments');
现在,如果您想要编写一个与众不同的集成测试。在那种情况下,我仍然使用间谍,但你实际上是在执行这些依赖。一般来说,不需要测试您的依赖项,因为它们也应该单独测试。此外,如果他们来自可信赖的来源,则不需要测试其他人的API。