spyon用于监视对象方法,记录调用并可劫持行为:默认仅记录不干扰原逻辑;通过and.callfake等链式调用可替换执行、返回值或抛错;需作用于自有属性,劫持后无法自动恢复原方法。

spyOn 是 Jasmine 测试框架提供的核心工具,用于“监视”(spy)对象上的某个方法,记录其调用情况(如是否被调,传了什么参数,返回什么值),并可选择性地“劫持”(即替换)其原始行为。
1. 基本监视:只记录,不干扰原方法
默认情况下,spyOn(obj, 'methodName') 仅创建一个 spy,**不会改变原方法逻辑**,原方法仍会正常执行:
const calculator = {
add: (a, b) => a + b
};
spyOn(calculator, 'add'); // 创建 spy,但 add 仍照常运行
calculator.add(2, 3); // ✅ 正常执行,返回 5
console.log(calculator.add.calls.count()); // → 1
console.log(calculator.add.calls.argsFor(0)); // → [2, 3]
2. 劫持执行:用 and.callFake() 替换原逻辑
要真正“劫持”方法、自定义执行逻辑,需链式调用 and.callFake():
- 传入一个函数,它会在原方法被调用时执行
- 原方法体将被完全跳过
- 适合模拟异步、抛错、返回固定值等场景
spyOn(calculator, 'add').and.callFake((a, b) => {
console.log('add called with:', a, b);
return -1; // 强制返回错误码
});
console.log(calculator.add(2, 3)); // → -1(不是 5!)
3. 其他常用劫持方式
除了 callFake,Jasmine 还提供几种快捷劫持策略:
-
and.returnValue(value):直接返回固定值(同步) -
and.returnValues(v1, v2, ...):按调用顺序依次返回不同值 -
and.throwError(msg):每次调用都抛出指定错误 -
and.callThrough():保留原方法执行,同时记录调用(相当于“增强监视”)
spyOn(calculator, 'add').and.returnValue(999);
console.log(calculator.add(1, 1)); // → 999(无视参数)
spyOn(console, 'log').and.callFake(msg => {
// 拦截所有 console.log,做日志审计或静音
});
4. 注意事项与常见陷阱
使用 spyOn 时需特别注意:
- 目标方法必须是对象的自有属性(own property),不能是原型链继承来的方法(如 Array.prototype.push),否则报错
- 若方法是箭头函数或绑定函数(
fn.bind(this)),需确保 spy 挂载在它实际所属的对象上 - 劫持后若想恢复原行为,可用
spyObj.calls.reset()清除记录,但无法自动还原方法——需手动重新赋值或在测试前备份 - 在 Angular 中测试组件方法时,推荐对组件实例本身 spyOn(如
spyOn(component, 'onClick')),而非通过this或类名











