1

我正在阅读http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf(尤其是第 8 页)并观看 Misko 关于编写可测试代码的 Youtube 视频,我想到 Angular 的方式DI 是否强迫你违反得墨忒耳法则。

从 PDF 中简化,一个违反得墨忒耳定律的 Java 构造函数示例:

class AccountView {
  boolean isAdmin;
  AccountView(AccountService) {
    isAdmin = AccountService.getCurrentUser().getProfile().isAdmin();
  }
}

因为该类只需要用户是否是管理员,而不需要 AccountService。

似乎 Angular 用它的 DI 强迫你打破得墨忒耳定律。我看不到以下内容的替代方案:

.controller('AccountServiceController', 
  ['AccountService', 
  function(AccountService) {
    this.user = AccountService.getCurrentUser().getProfile().isAdmin();
  }]
);

如果这是一个控制器,我们可以注入一个用户,它是一个控制器,一个具有解析参数的路由器,但不适用于一般情况。有什么想法吗?请注意,我假设只有 AccountService 是一个单例,并且每个后续对象都是一个实例(并且不能是 DI)。

4

1 回答 1

1

我不确定您提供的 Angular 示例或一般的 Angular DI 是否违反了 demeter 定律。Angular 依赖注入允许您编写非常可测试的代码。

让我们假设实际AccountService.getCurrentUser();是一个非常昂贵的网络操作。我们绝对不想在测试中调用这个方法。使用 Angular 的依赖注入,我们可以模拟AccountService,所以我们不必调用真正的依赖注入。

让我们为 编写一个测试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's 的内部。

于 2014-12-18T06:22:14.163 回答