如何使用Jasmine监视对象字段的赋值操作?
如何用Jasmine断言对象方法对字段的赋值操作?
问题背景
你想要测试testObj.testObjFunc方法是否会把testObj.testObjField字段赋值为"foo",测试对象和你尝试的代码如下:
测试对象:
const testObj = { testObjField: null, testObjFunc: function() { this.testObjField = "foo"; } }
你尝试的测试代码:
//arrange const testObj = { testObjField: null, testObjFunc: function () { this.testObjField = 'foo'; } }; const testObjTestObjFieldSpy = spyOnProperty(testObj, 'testObjField', 'set'); //act testObj.testObjFunc(); //assert expect(testObjTestObjFieldSpy).toHaveBeenCalledWith('foo');
运行后出现错误:
Error: : Property testObjField does not have access type set
错误原因
这个报错的核心是:testObjField是普通的数据属性,而不是带有setter的访问器属性。spyOnProperty的第三个参数'set'专门用于监视访问器属性的setter方法,普通字段没有这个访问器逻辑,所以Jasmine会报错提示找不到对应的set访问类型。
正确解决方案
这里提供两种常用的解决方式,你可以根据测试需求选择:
方案1:直接断言字段的最终值(推荐)
如果你的测试核心需求是验证方法执行后字段的结果是否正确,这是最简洁直接的方式——不需要监视赋值过程,直接检查最终状态:
describe('testObj.testObjFunc', () => { it('should set testObjField to "foo"', () => { // Arrange const testObj = { testObjField: null, testObjFunc: function () { this.testObjField = 'foo'; } }; // Act testObj.testObjFunc(); // Assert expect(testObj.testObjField).toBe('foo'); }); });
方案2:监视赋值动作(适用于需要跟踪赋值过程的场景)
如果你确实需要确认赋值动作的细节(比如赋值次数、传入的参数),可以把普通字段改成带setter的访问器属性,再用spyOnProperty监视:
describe('testObj.testObjFunc', () => { it('should trigger the testObjField setter with "foo"', () => { // Arrange: 将普通属性转为访问器属性 let internalValue = null; const testObj = { get testObjField() { return internalValue; }, set testObjField(val) { internalValue = val; }, testObjFunc: function () { this.testObjField = 'foo'; } }; // 监视setter,同时保留原有的赋值逻辑(and.callThrough()) const setterSpy = spyOnProperty(testObj, 'testObjField', 'set').and.callThrough(); // Act testObj.testObjFunc(); // Assert expect(setterSpy).toHaveBeenCalledWith('foo'); expect(testObj.testObjField).toBe('foo'); // 同时验证最终值正确 }); });
总结
- 优先选择方案1,因为测试的核心是验证业务逻辑的结果,而不是内部的赋值动作;
- 只有当你需要跟踪赋值的具体过程(比如统计调用次数、验证参数)时,才需要使用方案2的访问器属性+setter监视方式。
内容的提问来源于stack exchange,提问作者manymanymore
相关产品推荐
相关产品推荐

