AngularJS Jasmine 中具有服务依赖性的单元测试控制器

AngularJS Unit Testing Controller w/ service dependency in Jasmine

我是测试新手,我一直在努力寻找对具有服务依赖性的 AngularJS 控制器进行单元测试的最佳策略。这是源代码:

app.service("StringService", function() {
    this.addExcitement = function (str) {
        return str + "!!!";
    };
});

app.controller("TestStrategyController", ["$scope", "StringService", function ($scope, StringService) {
    $scope.addExcitement = function (str) {
        $scope.excitingString = StringService.addExcitement(str);
    };
}]);

我目前正在使用的测试:

describe("Test Strategy Controller Suite", function () {
    beforeEach(module("ControllerTest"));

    var $scope, MockStringService;

    beforeEach(inject(function ($rootScope, $controller) {
        $scope = $rootScope.$new();
        MockStringService = jasmine.createSpyObj("StringService", ["addExcitement"]);
        $controller("TestStrategyController", {$scope: $scope, StringService: MockStringService});
    }));

    it("should call the StringService.addExcitement method", function () {
        var boringString = "Sup";
        $scope.addExcitement(boringString);
        expect(MockStringService.addExcitement).toHaveBeenCalled();
    });
});

这个测试通过了,但我对某些事情感到困惑:如果我更改服务中方法的名称(假设我将其称为 addExclamations 而不是 addExcitement 但不是它在哪里在控制器中使用(仍然说$scope.excitingString = StringService.addExcitement(str);),即使我的控制器现在坏了,我的测试仍然通过。但是,一旦我也更改了控制器中的方法名称,以修复由更改服务的方法名称,我的 tests 中断,因为它试图调用旧的 addExcitement 方法。

这表明我需要通过将 jasmine 间谍对象行更改为 MockStringService = jasmine.createSpyObj("StringService", ["addExclamations"]);.

来手动使方法名称与服务保持同步

所有这些对我来说似乎都是倒退的,因为我觉得当我更改服务的方法名称而不更改控制器引用该服务名称的方式时,我的测试应该会中断。但是我不确定如何在这里两全其美,因为如果我希望我的测试以某种方式跟踪该服务名称,那么当我更改两个方法名称时,它就无法再次通过服务和控制器,因为 spyObj 仍然具有旧名称。

如果您对此背后的策略有任何见解或建议,我们将不胜感激。我将把这个教给一些学生,我主要是想确保我在这方面遵循了最佳实践。

我想说这是测试代码工作方式的预期结果,只是因为您创建了一个 "brand new" 模拟服务对象。我想你知道我在说什么。

我通常做的是获取服务实例并模拟方法,而不是创建一个全新的模拟对象。

   beforeEach(inject(function ($rootScope, $controller, $injector) {
       $scope = $rootScope.$new();
       MockStringService = $injector.get('StringService'); 
       spyOn(MockStringService , 'addExcitement').andReturn('test');
       $controller("TestStrategyController", {$scope: $scope, StringService: MockStringService});
   }));

请注意 andReturn() 是一个 jasmine 1.x 方法,取决于您使用的版本,您可能需要稍微更改代码。

这样一来,如果您更改 StringService 中的方法名称,您应该会从 spyOn() 方法中得到错误,因为该方法不再存在。

另一件事是,您不必像我那样使用 $injector 来获取服务实例,实际上您可以直接注入您的服务。我不记得我为什么这样做了。 :)