单元测试报错:部分测试触发了整页重载
解决单元测试报错:"Some of your tests did a full page reload!"
嘿,这个问题我之前在做Angular单元测试时也踩过坑!报错的原因非常直接——你的业务代码里执行了this.$window.location.href = ...,这行代码会触发完整的页面跳转/重载,而单元测试环境(比如Karma+Jasmine)不允许测试过程中出现这类会中断测试流程的操作,所以就抛出了这个错误。
问题根源拆解
单元测试的核心是在隔离的模拟环境里验证业务逻辑的正确性,而不是真的去触发真实的浏览器行为(比如页面跳转、文件下载)。当你在测试中调用DownloadResults()后,httpBackend.flush()会触发Promise的回调,进而执行$window.location.href的赋值,这直接触发了页面重载,打断了测试的执行。
两种解决方案
方案1:Mock掉$window对象(推荐)
我们可以在测试中提供一个模拟的$window对象,替换掉Angular注入的真实$window,这样既可以验证跳转URL是否正确,又不会真的触发页面跳转。
首先在测试的初始化阶段mock $window:
let mockWindow; let yourConfigMock; // 假设你也需要mock $config服务 beforeEach(() => { // 模拟$window对象,只保留我们需要的location属性 mockWindow = { location: { href: '' } }; // 模拟你的配置服务 yourConfigMock = { serverAddress: 'http://1.2.3.4/' }; // 注入mock对象到测试模块 module('yourAppModule', ($provide) => { $provide.value('$window', mockWindow); $provide.value('$config', yourConfigMock); }); // 后续的controller、scope、httpBackend初始化代码... });
然后修改测试用例,添加对跳转URL的验证:
it('should download test results', () => { expect(scope.downloading).toBeFalsy(); httpBackend .expectGET('http://1.2.3.4/downloads') // 注意:原代码里的"dowloads"拼写错误,这里修正为downloads .respond(mockedProductTest); controller.DownloadResults(); expect(scope.downloading).toBeTruthy(); httpBackend.flush(); expect(scope.downloading).toBeFalsy(); // 验证是否正确设置了跳转URL,而不是真的跳转 expect(mockWindow.location.href).toBe( `${yourConfigMock.serverAddress}download/TestResultszipFullPath=${mockedProductTest}` ); });
方案2:用Spy监听$window.location.href的赋值
如果你不想完全替换$window,也可以用Jasmine的spyOnProperty来监听location.href的setter,阻止它执行真实的跳转:
it('should download test results', () => { // 监听location.href的setter,并且不执行真实逻辑 spyOnProperty($window.location, 'href', 'set').and.callFake(() => {}); expect(scope.downloading).toBeFalsy(); httpBackend .expectGET('http://1.2.3.4/downloads') .respond(mockedProductTest); controller.DownloadResults(); expect(scope.downloading).toBeTruthy(); httpBackend.flush(); expect(scope.downloading).toBeFalsy(); // 验证spy是否被调用,并且传入了正确的URL expect($window.location.href).toHaveBeenCalledWith( `${yourConfigMock.serverAddress}download/TestResultszipFullPath=${mockedProductTest}` ); });
额外注意点
- 你的业务代码里有一个拼写错误:
${this.$config.serverAddress}downloads}这里多了一个闭合的大括号,应该改为downloads,不然真实环境中会请求错误的URL。 - 单元测试的原则是测试逻辑,而非副作用,所以mock外部依赖(比如
$window、$http)是常规操作,不要试图在单元测试中触发真实的下载或跳转行为。
内容的提问来源于stack exchange,提问作者Dan Murphy
相关产品推荐
相关产品推荐

