所以我有这样的功能:
function initializeView() {
var deferred = $q.defer();
var deleteOrUploadToBestMoments = this.deleteOrUploadToBestMoments;
var checkAndDeleteExpiredMoments = this.checkAndDeleteExpiredMoments;
getNearbyMoments()
.then(deleteOrUploadToBestMoments)
.then(checkAndDeleteExpiredMoments).then(function(moments) {
//omitted
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
};
我想用单元测试来测试这个功能。这是我的测试:
it('Should call initializeView', function(done) {
spyOn(service, 'getNearbyMoments').and.callFake(function() {
console.log("MOCKED getNearbyMoments");
return $q.resolve(mockOutMoments());
});
spyOn(service, 'deleteOrUploadToBestMoments').and.callFake(function() {
console.log("MOCKED deleteOrUploadToBestMoments");
return $q.resolve();
});
spyOn(service, 'checkAndDeleteExpiredMoments').and.callFake(function() {
console.log("MOCKED checkAndDeleteExpiredMoments");
return $q.resolve();
});
service.initializeView().then(function(moments) {
//omitted
done();
});
$scope.$apply();
});
问题出在spyOn函数上。它并没有嘲弄正确的功能。但是,如果我在生产代码中的getNearbyMoments前面添加一个'this',它会正确地模拟它:
function initializeView() {
var deferred = $q.defer();
var deleteOrUploadToBestMoments = this.deleteOrUploadToBestMoments;
var checkAndDeleteExpiredMoments = this.checkAndDeleteExpiredMoments;
this.getNearbyMoments()
.then(deleteOrUploadToBestMoments)
.then(checkAndDeleteExpiredMoments).then(function(moments) {
//omitted
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
};
我可以在我的生产代码中的所有函数调用前面添加一个'this',但当'this'的上下文发生变化时,这就成了一个问题。另外,我不需要改变我的生产代码只是为了让我的测试变得快乐 - 这让我真的想弄清楚我在测试中做错了什么,所以我没有对一个潜在的巨大问题进行创可贴
编辑:
显然我正在使用'this'正确地做到这一点。但问题是每当我这样做时,我都会收到错误
'TypeError: this.getNearbyMoments is not a function`
继承我的代码:
function initializeView() {
var deferred = $q.defer();
var deleteOrUploadToBestMoments = this.deleteOrUploadToBestMoments;
var checkAndDeleteExpiredMoments = this.checkAndDeleteExpiredMoments;
var getNearbyMoments = this.getNearbyMoments;
this.getNearbyMoments()
.then(deleteOrUploadToBestMoments)
.then(checkAndDeleteExpiredMoments).then(function(moments) {
//omitted
}, function(error) {
console.log("ERROR");
console.log(error);
deferred.reject(error);
});
return deferred.promise;
};
对于某些上下文,我的服务看起来像这样:
(function() {
angular.module('app.momentsService', [])
.service('momentsService', ['core', '$q', 'constants', 'logger', 'geolocation', 'awsServices', 'localStorageManager', momentsService]);
function momentsService(core, $q, constants, logger, geolocation, awsService, localStorageManager){
//Lots of other functions
this.checkAndDeleteExpiredMoments = checkAndDeleteExpiredMoments;
this.getNearbyMoments = getNearbyMoments;
this.deleteOrUploadToBestMoments = deleteOrUploadToBestMoments;
function getNearbyMoments() {
//Omitted...
};
function initializeView() {
//Well, you already know whats in here...
};
所以我很困惑,因为我在服务的顶部清楚地定义了函数,但由于某种原因它不知道它存在。
答案 0 :(得分:1)
spyOn(service, 'getNearbyMoments').and.callFake(function() { console.log("MOCKED getNearbyMoments"); return $q.resolve(mockOutMoments()); });
由于spyOn
的机制,无法修改对getNearbyMoments()
的调用。 initializeView
函数中的引用不能被spyOn
以特定方式覆盖。
您必须在this
前面添加getNearbyMoments
,以便使用spyOn
。
否则,您可以通过公开公开引用getNearbyMoments
并修改它来实现您想要的行为。但是你基本上会重新实现整个模拟系统和做一些比添加this
更复杂的事情。
答案 1 :(得分:0)
您的代码没有显示这一点,但我假设您可能正在执行类似
的操作var getNearbyMoments = this.getNearbyMoments;
在某个地方,因为你试图窥探service.getNearbyMoments
,但实际上并没有通过附加到服务的那个名称来调用函数。 如果就是这种情况,我的猜测是这是一个javascript引用问题。 spyOn的工作原理是这样的(但更复杂):
function(obj, method) {
var originalFn = obj[ method ];
obj[ method ] = function() {
// do spy stuff
// and potentially call the original
// depending what you do with the spy
originalFn()
}
}
因为您已将原始函数分配给它自己的变量,所以当该函数被spyOn
包装时,它不再指向相同的引用。
在将函数重新分配给局部变量之前,您需要先使用this
(或service
)或监视函数。同样,没有看到更多的代码使得这很难评估。
有关此参考问题的证明,请尝试:
var obj = {
foo: function() {}
};
var foo = obj.foo;
spyOn(obj, 'foo')
foo();
expect(obj.foo).to.haveBeenCalled() // -> false
关于this
不同的问题。 。 。我总是定义这样的服务:
angular.module('app').factory('SomeService', function() {
var service = {
foo: function() {
service.bar();
},
bar: function() {
console.log('bar');
}
};
return service;
});
这样,服务中的所有内容都使用本身对自身的引用,而这种引用永远不会改变。
答案 2 :(得分:0)
那个怎么样=这个?
代码中的... 那=上下文 that.getNearbyMoments() 。然后(deleteOrUploadToBestMoments)
并且在测试中:
...
that=service
service.initializeView()
答案 3 :(得分:0)
如果你这样做
this.getNearbyMoments()...
在initializeView()
内,您需要更改
function getNearbyMoments() {
//Omitted...
};
到
this.getNearbyMoments = function() {
//Omitted...
};