如何使AngularJS“私有”方法可测试?

时间:2016-04-22 12:55:37

标签: angularjs unit-testing

我有AngularJS服务。例如:

module.service('myService', function () {
  var privateFoo = function () {
    console.log('I am public foo');
  }, 
  self = this;

  self.publicFoo = function () {
    console.log('I am public foo');
  };
});

测试此服务:

it('test service', function () {
  expect(myService.publicFoo).toBeDefined(); // ok
  expect(myService.privateFoo).toBeDefined(); // not defined
});

像魅力一样工作。正如所料。

问题是我也想测试私有方法。为什么我需要这个?

想象一下,privateFoo使用/更改了一些私有对象。我有publicFooprivateFoo打电话给publicFoo。我想进行单元测试publicFoo。为此,我需要模拟publicFoo的所有依赖项以及从publicFoo调用的函数中的所有对象,即privateFoo

此类服务的示例:

module.service('myService', function (privateDep) {
  var privateFoo = function () {
    privateDep.get('123');
  },
  self = this;

  self.publicFoo = function () {
    privateFoo();
    return 5;
  };
});

publicFoo的测试:

it('test publicFoo', function () {
  expect(myService.publicFoo()).toEqual(5); // fail, privateDep.get trying to get get of undefined
});

所以,我需要模拟privateDep来测试publciFoo。

实际上,我想要的东西(例如,它不起作用,因为privateFoo是私有的:)):

it('test publicFoo', function () {
  spyOn(service, 'privateFoo');
  expect(myService.publicFoo()).toEqual(5); // fail, privateDep.get trying to get get of undefined
  expect(service.privateFoo).toHaveBeenCalled();
});

如果我将公开私有方法,但是,例如,使用某些前缀,例如_,则是可能的。像这样:self._privateFoo_前缀将显示API用户,该方法是私有的,他们不得使用它。

如何在AngularJS服务中使方法真正私密且可测试?在this post中很好地解决了控制器(带有$ scope)(好吧,方法不是真正的私有,但至少它们在其他范围内,控制器代码看起来非常好。

2 个答案:

答案 0 :(得分:0)

首先,您必须使用$ provide:

来模拟服务的所有依赖项
var privateDep = jasmine.createSpyObj('privateDep', ['get']);

beforeEach(function() {
  module('module name', function($provide) {
    $provive.value('privateDep', privateDep);
  });
});

这允许您在测试服务的公共方法时监视依赖项:

it('test publicFoo', function () {
  expect(myService.publicFoo()).toEqual(5);
  expect(privateDep.get).toHaveBeenCalledWith(123);
});

私有方法永远不可测试。这不是问题,因为私有方法的所有逻辑都是通过公共方法公开的,你可以测试它们。

但是,如果您的私有方法中有复杂的逻辑,您可以考虑将其解压缩为单独的服务并单独测试新服务。

答案 1 :(得分:0)

私人代码本质上是无法测试的,但是您可以通过在纯无状态函数中编写尽可能多的逻辑来减少琐碎的工作量。将您的无状态逻辑提取到单独的抽象组件中以进行单独测试,然后在私有函数中使用/组成它们。或者,如果共享这样的代码没有任何价值,那就别管它了。

单位等同于功能。一个现代的,用功能编写的js模块或组件可能包含20个私有函数,这些函数在总的30行中定义为琐碎的功能,但只公开了2个公共函数。一个 unit 是可以被其他对象使用的东西,因此是由其接口而不是其内容定义的。相反,仅使用自己的个人私有功能的公共功能不是接口,而只是实现细节。

尝试整理实现的内部结构和操作只会使整个体系结构更加脆弱,同时又会增加单元测试的成本。毕竟,拥有接口的关键是创建松散的耦合并使实现可替换,这就是为什么接口应该简单,轻巧,范围狭窄,并通过实现连接到相对较少的其他的原因。 / p>

当很难进行测试时,通常表明系统设计不佳,而不是测试方法存在问题。尊重隐私的及其在制造黑盒子中无害的帮助方面。