You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何Mock AngularJS模块配置中的$stateProvider自定义方法

AngularJS测试中Mock $stateProvider自定义扩展方法的解决方案

问题背景

我们的AngularJS模块代码如下:

(function () {
  'use strict';

  angular
    .module('someModule', [])
    .config(config);

  config.$inject = ['$stateProvider'];
  function config ($stateProvider) {
    $stateProvider
      .appState({})
  }
})();

其中appState是为$stateProvider扩展的自定义方法,该方法来自外部项目,仅在运行时加载。

测试时,我们尝试在spec文件中覆写该方法:

beforeEach(function () {
  angular.mock.module('someModule', function ($stateProvider) {
      spyOn($stateProvider, 'appState').and.returnValue({
          stateName: 'mockState',
          url: '/mock-url'
      });
  });
});

但无论如何尝试,原方法始终被调用,无法覆写。若不提前Mock该方法,模块初始化会报错:

Error: [$injector:modulerr] Failed to instantiate module someModule due to:
TypeError: $stateProvider.appState is not a function

请问如何Mock ui-router的$stateProvider这类AngularJS模块配置提供者?

解决方案

核心问题在于:模块的config块会在你尝试在angular.mock.module的配置函数中Mock之前就执行,所以你的Spy根本没来得及生效;而如果提前不定义appState,模块初始化时又会因为找不到方法报错。

正确的做法是在加载目标模块之前,先给$stateProvider添加Mock的appState方法,以下是两种可行方案:

方案一:分步Mock与模块加载

beforeEach(function () {
  // 1. 先创建临时模块,给$stateProvider添加基础的appState方法
  angular.module('mockStateExt', [])
    .config(function ($stateProvider) {
      // 实现链式调用的基础方法,避免模块初始化报错
      $stateProvider.appState = function() {
        return $stateProvider;
      };
    });

  // 2. 先加载临时Mock模块,再加载目标业务模块
  angular.mock.module('mockStateExt', 'someModule');

  // 3. 模块加载完成后,替换为带监听的Spy
  inject(function ($stateProvider) {
    spyOn($stateProvider, 'appState').and.returnValue({
      stateName: 'mockState',
      url: '/mock-url'
    });
  });
});

方案二:简化前置Mock写法

如果不需要精细监听调用,仅需让模块初始化通过,可直接在加载目标模块前完成Mock:

beforeEach(function () {
  // 先执行Mock配置,确保appState在模块config前存在
  angular.mock.module(function ($stateProvider) {
    $stateProvider.appState = jasmine.createSpy('appState').and.returnValue($stateProvider);
  });

  // 再加载目标模块
  angular.mock.module('someModule');
});

原理说明

AngularJS的模块加载按顺序执行,只要保证$stateProvider.appState方法在目标模块的config块执行前被定义,就能避免初始化报错;后续再替换为Spy则可以捕获方法调用并返回自定义值。

内容的提问来源于stack exchange,提问作者OrangeJuice1-

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:03:21