问题描述
在指令中模拟$ stateParams的最佳方法是什么? $ stateParam成员将根据测试进行更改。
What is the best approach to mock $stateParams in a directive? $stateParam members will be changed according to the test.
我可以使用$ controller('ctrl',$ stateParams)在控制器中轻松模拟$ stateParams,但不知道如何修改注入指令的$ stateParams。
I can easily mock $stateParams in a controller using $controller('ctrl', $stateParams) but dont know how to modify $stateParams that gets injected into the directive.
我已经使用下面的装饰$ stateParams的路线,但只能在我创建模块时声明。正如我所提到的,$ stateParam成员将通过不同的测试多次更改。
I've gone the route of decorating $stateParams with the below but can only declare that when i create the module. as i mentioned, $stateParam members will change many times through the different tests.
beforeEach(angular.mock.module(function ($provide) {
$provide.provider('$stateParams', function () {
return {
myStateParam: true,
myOtherStateParam: 'some text'
};
});
}));
推荐答案
使用指令控制器处理与路径相关的逻辑( $ state
/ $ route
)总是一个好主意,这是控制器的工作而不是链接功能。
Using directive controller to handle route-related logic ($state
/$route
) is always a good idea, that's the job for controller and not for linking functions.
如果指令可以通过测试其控制器并模拟其本地依赖关系来完全测试(积分转到JB Nizet的回答)它故事的结尾:
In the case of a directive that could be tested completely just by testing its controller and mocking its local dependencies (credits go to JB Nizet's answer) it is the end of the story:
$controller('...', { $scope: scope, $stateParams: { ... });
对于带有 $ compile的常规指令规范,情况并非如此
。 $ compile
在内部使用 $ controller
来实例化控制器,但不接受本地模拟其依赖项。
It isn't the case for regular directive spec with $compile
. $compile
uses $controller
internally to instantiate the controller but doesn't accept locals to mock its dependencies.
有几种方法可以解决这个问题。
There are several ways to handle this.
如果 $ stateParams
不必直接注入规范并因此未实例化,则可以在模块引导后定义其值。当每个规范只应模拟一次服务实例值时,不要再看了:
If $stateParams
does not have to be injected into spec directly and thus is uninstantiated, its value can be defined after the module was bootstrapped. When service instance value should be mocked only once per spec, look no further:
var stateParams;
beforeEach(module(('...', function ($provide) {
$provide.factory('$stateParams', function () {
return stateParams;
});
}));
it('...', inject(function ($compile) {
stateParams = { ... };
...
$ provide.constant
$ provide
服务提供商在模块引导后(重新)定义服务:
$provide.constant
$provide
service provider can be exposed as service instance to (re)define services after the module was bootstrapped:
beforeEach(module('...', function ($provide) {
$provide.value('$provide', $provide);
}));
it('...', inject(function ($provide, $compile) {
$provide.constant('$stateParams', { ... });
...
$ provide.constant
在这种情况下更可取,因为它将取代缓存的 $ stateParams
服务实例,如果它之前被注入,whi le $ provide.value
不会。
$provide.constant
is preferable in this case because it will replace cached $stateParams
service instance if it was injected before, while $provide.value
won't.
angular.copy
(UI路由器0.x实际上使用它来保持 $ stateParams
对象最新的)可用于保留现有的对象引用但替换其内容:
angular.copy
(which actually was used by UI Router 0.x to keep $stateParams
object up to date) can be used to preserve existing object references but replace its contents:
it('...', inject(function ($stateParams, $compile) {
angular.copy({ ... }, $stateParams);
...
$ state.params
$ state
服务鲜为人知属性 params
,它可以用作在整个代码中替换 $ stateParams
服务以提高其可测试性。
$state.params
$state
service has little-known yet publicly exposed to API property params
, it can be used as a replacement for $stateParams
service all over the code to improve its testablity.
$ stateParams
和 $ state.params
可能不会引用同一个对象,因此必须选择其中一个。
$stateParams
and $state.params
may not refer to the same object, so the choice has to be made in favour of one of them.
由于未经请求的 $ state
注入导致测试脆弱的风险,它可以像
At the cost of the risk of test fragility due to of unsolicited $state
injection, it can be as neat as
it('...', inject(function ($state, $compile) {
$state.params = { ... };
...
这篇关于指令中的angular + jasmine + mock $ stateParams的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!