Angularjs 如何在Jasmine单元测试中模拟模块API依赖关系?

Angularjs 如何在Jasmine单元测试中模拟模块API依赖关系?,angularjs,unit-testing,dependency-injection,jasmine,Angularjs,Unit Testing,Dependency Injection,Jasmine,我有一个案例来单元测试自定义角度指令myApp,并设置了必要的karma和jasmine配置。 在这个测试用例中,我尝试模拟并存根myApp的依赖模块,它是服务-services.FuzzAPI。 因为我没有访问services.FuzzAPI文件的权限,所以无法使用sinon对其进行模拟 在Angular和Jasmine文档之后,我在.spec文件中设置了spec文件,并遵循以下步骤 首先,在这之前,每个人都根据 并注册myApp模块,以使用angular.mock.module进行测试 然后

我有一个案例来单元测试自定义角度指令
myApp
,并设置了必要的karma和jasmine配置。 在这个测试用例中,我尝试模拟并存根
myApp
的依赖模块,它是服务-
services.FuzzAPI
。 因为我没有访问services.FuzzAPI文件的权限,所以无法使用sinon对其进行模拟

在Angular和Jasmine文档之后,我在
.spec
文件中设置了spec文件,并遵循以下步骤

  • 首先,在这之前,每个人都根据 并注册
    myApp
    模块,以使用
    angular.mock.module
    进行测试
  • 然后在第二个beforeach中使用$injector传递
    myApp
    指令的$compile步骤的模拟FuzzAPI 但是,即使在模拟了依赖关系之后,我仍然得到一个
    $injector:modulerr
    告诉我services.FuzzAPI不可用。 这告诉我soemthing与
    服务的注册有误。FuzzAPI
    依赖项:

     LOG LOG: 'before mock'
     LOG LOG: 'after mock'
     Error: [$injector:modulerr] Failed to instantiate module myApp due to:
            Error: [$injector:modulerr] Failed to instantiate module services.FuzzAPI due to:
            Error: [$injector:nomod] Module 'services.FuzzAPI' is not available! You either misspelled the module name or forgot to load it
    
    问题:

    如何在Jasmine单元测试中模拟指令依赖性

    查看代码,我可以看到这个错误在每个(inject(function($rootScope,$compile$injector){ 因为在抛出错误之前,inject
    beforeach
    中的console.log不会被触发

    指令和测试规范的要点:

    //my-app.js

    (function() {
    
      var component = {
        id: "myApp",
        name: "My App",
        templateUrl: localStorage.getItem("baseURL") + "my-app/my-app.html"
      };
    
      component.ui = angular.module("myApp", ["services.FuzzAPI"]);
      component.ui.directive("myApp", widgetComponent);
    
      function widgetComponent(FuzzAPI) {
    
        // main widget container
        function widgetContainer(scope, element, params) {
          var api = new FuzzAPI(params);
    
          scope.greeting = "Hello World";
    
          var setGreeting = function(message){
            scope.greeting = message;  
          };
    
          api.onDataEvent("onFuzzEvent", function(data) {
            scope.greeting = data;
          });
    
    
          element.on("$destroy", function() {     
            api.unregister();
            scope.$destroy();
          });
        }
    
        return {
          scope: {},
          replace: true,
          link: widgetContainer,
          templateUrl: component.templateUrl
        };
      }
    })();
    
    //my-app.spec.js

    describe("myApp", function() {
    
      var $scope, $compile, $provide, $injector, element, fuzzAPIMock, FuzzAPIProvider;
    
      beforeEach(function(){
    
        //mock service FuzzAPI via service provider
        fuzzAPIMock = {
          greeting : "123",
          initializeCurrentItem : function () {
            return true;
          }
        };
    
        console.log("before mock");
    
        //register module and mock dependency
        angular.mock.module(function($provide) {
                $provide.value('services.FuzzAPI', fuzzAPIMock);
        });
    
        angular.mock.module("myApp");
    
        console.log("after mock");
    
    
      });
    
      beforeEach(inject(function($rootScope, _$compile_, $injector) {
    
        console.log("in inject..");
        FuzzAPIProvider = $injector.get('services.FuzzAPI');
        $scope = $rootScope.$new(), //create instance of rootScope
        $compile = _$compile_; 
        console.log("in inject before compile..");
        element = $compile("<my-app></my-app>")($scope); // compile attaches directives to HTML template
        console.log("in inject after compile..");
        $scope.$digest(); //loop through DOM watchers, check values and trigger listeners
      }));
    
    
    });
    
    描述(“myApp”,函数(){
    var$scope、$compile、$provide、$injector、element、fuzzAPIMock、FuzzAPIProvider;
    beforeach(函数(){
    //通过服务提供者模拟服务API
    fuzzAPIMock={
    问候语:“123”,
    initializeCurrentItem:函数(){
    返回true;
    }
    };
    控制台日志(“模拟前”);
    //寄存器模块和模拟依赖项
    angular.mock.module(函数($provide){
    $provide.value('services.FuzzAPI',fuzzAPIMock);
    });
    角度模拟模块(“myApp”);
    控制台日志(“模拟后”);
    });
    beforeach(注入(函数($rootScope,$compile,$injector){
    console.log(“插入…”);
    FuzzAPIProvider=$injector.get('services.FuzzAPI');
    $scope=$rootScope.$new(),//创建rootScope的实例
    $compile=\$compile;
    log(“在编译之前插入…”;
    element=$compile(“”($scope);//compile将指令附加到HTML模板
    log(“编译后插入…”);
    $scope.$digest();//循环DOM监视程序、检查值和触发器侦听器
    }));
    });
    
    错误:[$injector:nomod]模块“services.FuzzAPI”不可用!您可能拼错了模块名称或忘记加载它

    表示应该模拟的是
    services.FuzzAPI
    模块,而不是服务。根据提供的代码,服务名称是
    FuzzAPI
    ,应该用构造函数模拟,而不是对象

    为了使丢失的模块不会导致错误,应将其存根。可以在顶级
    description
    块中存根一次:

    beforeAll(() => {
      angular.module('services.FuzzAPI', []);
    });
    
    恢复存根模块是不可能的(至少在没有黑客攻击的情况下是不可能的),但如果真正的模块不应该出现在测试中,这并不是一个问题

    然后可以像往常一样模拟服务。如果它是
    FuzzAPI
    :,那么应该是

    fuzzAPIMock = jasmine.createSpy('').and.returnValue({
      greeting : "123",
      initializeCurrentItem : jasmine.createSpy('').and.returnValue(true)
    });
    
    angular.mock.module(function($provide) {
      $provide.value('FuzzAPI', fuzzAPIMock);
    });
    
    最好使用Jasmine spies作为模拟/存根函数

    错误:[$injector:nomod]模块“services.FuzzAPI”不可用!您可能拼错了模块名称或忘记加载它

    表示应该模拟的是
    services.FuzzAPI
    模块,而不是服务。根据提供的代码,服务名称是
    FuzzAPI
    ,应该用构造函数模拟,而不是对象

    为了使丢失的模块不会导致错误,应将其存根。可以在顶级
    description
    块中存根一次:

    beforeAll(() => {
      angular.module('services.FuzzAPI', []);
    });
    
    恢复存根模块是不可能的(至少在没有黑客攻击的情况下是不可能的),但如果真正的模块不应该出现在测试中,这并不是一个问题

    然后可以像往常一样模拟服务。如果它是
    FuzzAPI
    :,那么应该是

    fuzzAPIMock = jasmine.createSpy('').and.returnValue({
      greeting : "123",
      initializeCurrentItem : jasmine.createSpy('').and.returnValue(true)
    });
    
    angular.mock.module(function($provide) {
      $provide.value('FuzzAPI', fuzzAPIMock);
    });
    
    最好使用Jasmine spies作为模拟/存根函数