我正在阅读http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf(请参阅,尤其是第8页)并观看Misko的Youtube视频,编写可测试的代码,并且我发现Angular的方式DI会强迫您违反Demeter法则。
从PDF中简化,一个违反Demeter法则的Java构造函数的例子:
class AccountView {
boolean isAdmin;
AccountView(AccountService) {
isAdmin = AccountService.getCurrentUser().getProfile().isAdmin();
}
}
因为该类只需要用户是否为admin,而不是AccountService。
似乎Angular强迫你用它的DI打破Demeter的规律。我看不到以下的替代方案:
.controller('AccountServiceController',
['AccountService',
function(AccountService) {
this.user = AccountService.getCurrentUser().getProfile().isAdmin();
}]
);
如果这是一个控制器,控制器是具有解析参数的路由器,我们可以注入一个用户,但不适用于一般情况。有什么想法吗?请注意,我假设只有AccountService是一个单例,并且每个后续对象都是一个实例(并且不能是DI)。
答案 0 :(得分:1)
我不确定您提供的Angular示例或Angular DI一般是否违反了demeter法则。角度依赖注入允许您编写非常可测试的代码。
假设真实AccountService.getCurrentUser();
是一个非常昂贵的网络操作。我们绝对不想在测试中调用此方法。使用Angular的依赖注入,我们可以模拟AccountService
,因此我们不必调用真实的。{/ p>
让我们为AccountServiceController
编写一个测试:
.controller('AccountServiceController',
['$scope', 'AccountService',
function($scope, AccountService) {
$scope.user = AccountService.getCurrentUser();
}]
);
describe('AccountServiceController function', function() {
describe('AccountServiceController', function() {
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
$controller('AccountServiceController', {
$scope: $scope
AccountService: {
getCurrentUser: function () {
return {
name: 'Austin Pray',
id: 1111
};
}
}
});
}));
it('should get the current user', function() {
expect(typeof $scope.user.name).toBe('string');
});
});
});
我们避免了昂贵的网络操作,并且控制器没有以任何方式耦合到AccountService
的内部。