Karma单元测试:如何模拟工厂中返回Promise的私有函数
如何模拟AngularJS TestFactory中依赖Promise的私有函数
嘿,这个问题其实是AngularJS单元测试里的常见场景——因为私有函数是工厂闭包内部的,咱们根本没法直接访问并模拟它。不过没关系,单元测试的核心是测试公开API,同时隔离它的外部依赖,所以咱们可以换个思路:不去直接mock私有函数privateFunction,而是模拟它依赖的callerfactory.Caller及其init()方法的返回值,这样就能间接控制privateFunction的行为,进而完成对publicFunction的测试。
下面以Jasmine+AngularJS测试框架为例,给你一步步拆解实现:
1. 搭建测试环境,注入并Mock依赖
首先,我们需要在测试用例中注入TestFactory,同时把真实的callerfactory替换成我们的mock版本,这样就能完全控制它的行为:
describe('TestFactory', function() { var TestFactory, $q, $rootScope, mockCallerfactory; // 加载你的应用模块 beforeEach(module('yourAppModuleName')); // 记得替换成你实际的模块名 // 用mock的callerfactory替换真实依赖 beforeEach(module(function($provide) { mockCallerfactory = { Caller: jasmine.createSpy('Caller') // 创建一个间谍函数跟踪Caller构造函数 }; $provide.value('callerfactory', mockCallerfactory); })); // 注入测试需要的服务 beforeEach(inject(function(_TestFactory_, _$q_, _$rootScope_) { TestFactory = _TestFactory_; $q = _$q_; // 用来创建mock的Promise $rootScope = _$rootScope_; // 用来触发Angular的消化周期,执行Promise回调 }));
2. 模拟Caller实例的init()方法返回可控Promise
接下来,我们需要让Caller构造函数返回的实例拥有一个mock的init()方法,这个方法返回我们可以控制状态(resolved/rejected)的Promise:
beforeEach(function() { // 创建一个mock的Caller实例,带init方法 var mockCallerInstance = { // 这里让init返回一个resolved的Promise,你也可以换成$q.reject模拟失败场景 init: jasmine.createSpy('init').and.returnValue($q.when('mockSuccessData')) }; // 让Caller构造函数返回这个mock实例 mockCallerfactory.Caller.and.returnValue(mockCallerInstance); });
3. 测试publicFunction的行为
现在我们可以调用公开的publicFunction,验证它的逻辑是否符合预期,同时检查依赖是否被正确调用:
it('should trigger privateFunction logic and resolve with expected data', function(done) { // 调用要测试的公开函数 TestFactory.publicFunction('testInput').then(function(result) { // 验证Promise的返回结果是否符合预期(这里要和你privateFunction里resolve的值对应) expect(result).toBe('mockSuccessData'); // 验证Caller构造函数是否用正确的参数被调用 expect(mockCallerfactory.Caller).toHaveBeenCalledWith('testInput'); // 验证init方法是否被执行 expect(mockCallerfactory.Caller.returnValue.init).toHaveBeenCalled(); done(); // 异步测试需要调用done来标记完成 }); // 关键:Angular的Promise需要触发消化周期才能执行then回调 $rootScope.$digest(); }); });
几个关键要点:
- 为什么不直接mock私有函数?:私有函数是工厂内部的闭包变量,外部完全无法访问,所以单元测试的最佳实践是通过测试公开接口,同时隔离外部依赖来间接验证私有逻辑的正确性。
- 控制Promise状态:用
$q.when()创建成功的Promise,$q.reject()创建失败的Promise,再通过$rootScope.$digest()触发Angular的消化周期,让Promise的回调函数执行。 - 间谍函数的作用:Jasmine的
createSpy可以帮我们跟踪函数的调用情况,包括是否被调用、调用参数是什么,这是验证依赖是否正确交互的核心。
内容的提问来源于stack exchange,提问作者MojiTz
相关产品推荐
相关产品推荐

