AngularJS测试如何mock angular.element.injector().get解决TypeError报错
问题修复方案
报错的根本原因是单元测试运行时没有实际启动挂载的AngularJS应用实例,document.body上没有绑定应用的injector实例,所以调用injector()返回undefined,调用get方法就触发了类型错误。
以下是两种具体实现方案:
方案1:直接mock angular.element 逻辑(适配现有代码无需业务改造)
AngularJS生态最常用的测试组合是Jasmine+Karma,你可以在测试用例的前置钩子中添加如下mock逻辑:
// 测试前置钩子 beforeEach(function () { // 1. 先构造你需要的SomeElement服务mock对象 const mockSomeElement = jasmine.createSpyObj('SomeElement', ['你的方法1', '你的方法2']); // 如果不需要测方法调用,也可以直接写普通对象:const mockSomeElement = { xxx: '测试值' } // 2. mock angular.element方法,匹配document.body入参时返回带injector的对象 spyOn(angular, 'element').and.callFake(function (target) { if (target === document.body) { return { injector: function () { return { get: function (serviceName) { if (serviceName === 'SomeElement') return mockSomeElement; // 有其他需要通过injector获取的服务可以在这里扩展逻辑 return null; } } } } } // 其他场景走原生angular.element逻辑,不影响其他代码执行 return angular.element.originalApply(target); }); }); // 提前保存原生angular.element方法,避免mock污染 beforeAll(function () { angular.element.originalApply = angular.element; }); // 测试结束后恢复原生方法,避免用例间相互影响 afterAll(function () { delete angular.element.originalApply; });
如果你用的是其他测试框架(比如Mocha),把Jasmine的spyOn换成对应框架的mock方法即可,逻辑完全一致。
方案2:业务代码重构(更推荐,长期可维护性更高)
直接通过angular.element(document.body).injector().get()获取服务的写法耦合度很高,也不符合AngularJS的依赖注入设计规范,建议改成直接在控制器中注入依赖的方式:
// 改造后的控制器代码,直接声明依赖即可 angular.module('你的应用名').controller('你的控制器名', ['SomeElement', function (SomeElement) { function sendAnalytics(searchParams) { var analyticServiceCall = SomeElement; // 原有业务逻辑不需要改动 }; }]);
改造后测试时不需要做任何全局mock,直接在初始化控制器的时候传入mock的SomeElement即可:
// 测试用例中初始化控制器的逻辑 beforeEach(inject(function ($controller) { const mockSomeElement = {}; // 你的mock对象 $controller('你的控制器名', { SomeElement: mockSomeElement }); }));
内容的提问来源于stack exchange,提问作者Code is Cheap Show me The Talk
相关产品推荐
相关产品推荐

