AngularJS单元测试控制器仅具有私有功能

时间:2015-07-09 08:34:06

标签: angularjs unit-testing

我有以下只有私人功能的控制器。我正在努力测试这个控制器。我应该测试它是否正在执行$ emit,因为ImageService已经过测试了吗?在这种情况下如何测试$ emit?或者我应该测试它是否正在调用ImageService.fetchImageStacks方法?在这种情况下,如何触发init函数?

(function (angular, global, undefined) {
'use strict';

var ImageController = {};

ImageController.$inject = [
    '$rootScope',
    '$log',
    'ImageService'
];

ImageController = function (
    $rootScope,
    $log,
    ImageService
) {

    var getImageStacks = function() {
        ImageService
            .fetchImageStacks()
            .success(function (result) {
                ImageService.setImageStacks(result);
                $rootScope.$emit('rootScope:imageStacksUpdated', result);
            })
            .error(function (){
                $log.error('Failed to get imageStackInfo file.');
            });
    };

    var init = function () {
        getImageStacks();
    };

    init();

    return {
        getImageStacks: getImageStacks
    };
}

angular.module('myApp')
    .controller('ImageController', ImageController);

})(angular, this);

1 个答案:

答案 0 :(得分:1)

您不应该测试外部世界无法使用的私人/内部方法( imho )。

有关该主题的一些资源(针对&反对):

话虽如此,你在控制器上暴露getImageStacks - 所以它不是私有方法。如果您要在测试套件中注销实例化控制器的结果,您应该看到类似的东西:

{ getImageStacks: function }

(在您的情况下为init(),只是getImageStacks的别名(也就是说,不需要init方法 - 您只需致电getImageStacks并完成它))。

无论如何,要写一些测试;

首先,您应stub ImageService beforeEach,因为我们对所述服务的内部实施不感兴趣,我们只对从控制器到服务的通信感兴趣。用于存根/嘲笑/间谍的优秀图书馆是sinonjs - 得到它,你不会后悔。

// Stub out the ImageService var ImageService = { fetchImageStacks: sinon.stub(), setImageStacks: sinon.stub() }; var $scope, instantiateController; beforeEach(function () { // Override the ImageService residing in 'your_module_name' module('your_module_name', function ($provide) { $provide.value('ImageService', ImageService); }); // Setup a method for instantiating your controller on a per-spec basis. instantiateController = inject(function ($rootScope, $controller, $injector) { ctrl = $controller('ImageController', { $scope: $rootScope.$new(), // Inject the stubbed out ImageService. ImageService: $injector.get('ImageService') }); }); }); 我建议你做这样的事情:

it('calls the ImageService.fetchImageStacks method on init', function () {
  instantiateController();
  expect(ImageService.fetchImageStacks).to.have.been.calledOnce;
});

it('calls the ImageService.setImageStacks on success', inject(function ($q, $timeout) {
  ImageService.getImageStacks.returns($q.when('value'));
  instantiateController();
  $timeout.flush();
  expect(ImageService.setImageStacks).to.have.been.calledOnce.and.calledWith('value');
}));

现在你有一个用于测试调用的存根ImageService,以及一个用传递给它的依赖项来实例化你的控制器的方法。

您可以运行一些示例规范;

subdirs = [x[0] for x in os.walk("/folders/")]
for subdir in subdirs:                                                                                          
    files = os.walk(subdir).next()[2] 
    for f in files:
        if ".txt" in f:
            with open(subdir + "/" + f) as inputfile:
                if not os.path.exists("/folder/"+year+"/"):
                    os.makedirs("/folder/"+year+"/")
                print "This should be true orelse there will be no copy :  ", os.path.isfile(subdir + "/" + f)     
                if os.path.isfile(subdir + "/" + f):       
                    shutil.copy(subdir + "/" + f, "/folder_to_copy_to/"+year+"/"+f)

我希望能够满足并回答你的问题;

  • 如果/何时应该/不应该测试内部实施。
  • 如何测试控制器的初始化。
  • 如何测试注入服务的方法。