Angular 1.5 && Async/Await && 茉莉花测试
Posted
技术标签:
【中文标题】Angular 1.5 && Async/Await && 茉莉花测试【英文标题】:Angular 1.5 && Async/Await && jasmine tests 【发布时间】:2017-04-23 01:03:41 【问题描述】:我已经到处找了,但还没有找到适合我的特殊情况的解决方案。
我们使用 Angular 1.5 和 Karma/Jasmine 设置进行单元测试。在最初的源代码中,我在控制器中使用了 ES2017 async/await。只要我在最后手动添加 $apply 的 $digest 似乎就可以正常工作。 比如:
async function loadData()
try
vm.isLoading = true;
vm.data = await DataService.getData();
$scope.$apply();
catch (ex)
vm.isLoading = false;
为了为这个特定的函数编写自动化测试,我尝试使用 Jasmine 的 spyOn
模拟 DataService.getData。所以,我做了这样的事情:
spyOn(DataService, 'getData').and.returnValue($q.when(fakeResult));
添加 spy 有效,但在运行测试时,代码似乎被击中并且无法使用 fakeResult
解析。我尝试在测试本身中添加 $digest/$apply 但无法修复它。我也做了很多研究,但仍然没有任何线索。
有人知道吗?
编辑:用$q
promises 测试相同的方法效果很好,但我真的很想使用 async/await...
【问题讨论】:
仅供参考,async/await
是 ES2017 的一部分,将于明年发布,而不是 ES7(今年发布)。
【参考方案1】:
我不知道您的设置是否类似,但在我们的环境中,我必须做一些事情来获得转译的 async/await 语句以在 jasmine 测试中解析。
在我们的测试中,我试图模拟出会返回承诺的服务。我发现返回$q.when
不起作用。相反,我必须返回实际的 A+ 标准 Promises。我的猜测是 Angular 的 $q 承诺并不完全符合标准,也不能作为替代品。
请注意,由于我们使用 PhantomJS 进行测试,因此我必须添加 polyfill 才能获得这些 Promise。
在我的测试中,很多时候我必须将一些期望语句包装在 setTimeout
块中。同样,我的假设是,promise 需要额外的“tick”来处理。
【讨论】:
【参考方案2】:所以没有结果的原因是因为await
之后什么都没有执行。当我在反应组件中测试async/await
时,我遇到了类似的问题。
我在某处发现了一种测试方法如下:
-
你必须使用类似于https://www.npmjs.com/package/jasmine-async-suite 的东西——这是我使用的。它适用于您期望得到承诺的异步测试。
还可能存在其他问题,即在 promise 解决后,测试停止,因为没有什么可以等待 :)。这可能非常棘手。
因此您必须手动调用该方法,在您的情况下为
DataService.getData()
,并使用.then()
方法,您可以在其中放置您的expect
语句 - 由于这一步,您的测试正在等待解决承诺.
这是我的代码示例(我也在测试中使用async
函数):
it.async('should call `mySpecialMethod`', async () =>
const arrayToResolve = [ data: 'data' ];
const SomeService = context.SomeService;
spyOn(props, 'mySpecialMethod');
spyOn(SomeService, 'myMethodReturningPromise');
.and.returnValue(Promise.resolve(arrayToResolve));
//the method `myMethodReturningPromise` is called in componentDidMount
const wrapper = mount(<MyReactComponent ...props />, context);
expect(SomeService.myMethodReturningPromise).toHaveBeenCalled();
//now I am calling the method again
await SomeService.myMethodReturningPromise();
//`mySpecialMethod` is calling after the `await` in my code
expect(props.mySpecialMethod).toHaveBeenCalled();
//after that I am changing the state
expect(wrapper.state().arrayToResolve).toEqual(arrayToResolve);
);
希望对你有帮助:)
【讨论】:
【参考方案3】:你可以使用库async-await-jasmine:
import * as angular from 'angular';
import 'angular-mocks';
import yourModule from "./your-module-path";
import LoadDataService from './load-data';
import $it from "async-await-jasmine";
import IRootScopeService from "angular";
describe('Calculator', () =>
let $httpBackend: angular.IHttpBackendService;
beforeEach(() =>
angular.mock.module(calculatorModule.name);
angular.mock.inject((_$httpBackend_) =>
$httpBackend = _$httpBackend_;
);
);
$it('should loadData', async () =>
$httpBackend.when('GET', '/loadData').respond('"value": 5');
let sum = loadData(1, 4);
$httpBackend.flush();
expect(await sum).toBe(10);
);
);
【讨论】:
以上是关于Angular 1.5 && Async/Await && 茉莉花测试的主要内容,如果未能解决你的问题,请参考以下文章