AngularJS单元测试$http服务时出现意外请求错误排查
问题原因与解决方案
咱们拆解这两个报错的核心本质,都是AngularJS单元测试中未正确Mock HTTP请求导致的,具体分两种情况逐一分析:
1. 第一个报错:Error: Unexpected request: GET api/Account/GetTest
这个问题的核心是测试用例中$httpBackend.expectGET()声明的URL,和服务里getTest函数实际发起请求的URL格式不匹配。
AngularJS的$http对URL的匹配是严格区分细节的——比如如果你的服务里写的是:
// 服务中的getTest函数 function getTest() { return $http.get('/api/Account/GetTest'); // 带开头斜杠 }
但测试用例里写的是不带斜杠的$httpBackend.expectGET('api/Account/GetTest'),这两个URL会被视为完全不同的请求,$httpBackend找不到对应的Mock规则,就会抛出"Unexpected request"错误。反过来,如果服务里不带斜杠、测试里带了,也会出现同样的问题。
2. 第二个报错:Error: Unexpected request: GET /app/views/login.html
当你调整测试URL匹配上getTest的请求后,为什么又出现模板请求的报错?这是因为你的getTest函数(或其依赖的逻辑)触发了路由跳转(比如请求失败后自动跳转到登录页),而AngularJS的路由模块(ngRoute或ui-router)在单元测试环境中,会尝试实际加载对应的模板文件——但你没有提前Mock这个模板请求,所以又触发了新的"Unexpected request"。
针对性解决方案
解决URL匹配问题
- 严格对齐URL格式:仔细检查服务中
$http.get()的URL是否带开头斜杠,让测试里的expectGET()和它完全一致。 - 用常量统一管理API地址:避免手动写URL出错,比如在项目中定义一个全局常量:
服务中调用时复用常量:// 项目中定义API基础地址 angular.module('yourApp').constant('API_BASE', '/api');
测试中直接注入这个常量来构造请求URL,从根本上避免URL拼写或格式不一致的问题。function getTest(API_BASE) { return $http.get(`${API_BASE}/Account/GetTest`); }
解决模板请求问题
有两种常见处理方式:
- Mock模板到
$templateCache:在测试的beforeEach中预加载模板内容,让路由不用实际请求文件:beforeEach(inject(function($templateCache) { // 用空内容Mock登录页模板,实际可根据测试需求编写模板片段 $templateCache.put('/app/views/login.html', '<div></div>'); })); - 阻止不必要的路由跳转:如果
getTest触发路由跳转是测试不需要的逻辑,可以Mock路由服务(比如$state或$location)来阻止实际跳转:beforeEach(inject(function($state) { // 拦截$state.go调用,不执行实际跳转 spyOn($state, 'go').and.callFake(() => {}); }));
额外注意事项
- 所有通过
$http发起的请求(包括间接触发的)都必须被Mock,否则都会抛出"Unexpected request"错误。 - 记得在测试断言前调用
$httpBackend.flush(),触发Mock请求的响应。 - 确保测试中正确注入了
ngMock模块,它提供了$httpBackend和$templateCache等核心测试工具。
内容的提问来源于stack exchange,提问作者ataravati
相关产品推荐
相关产品推荐

