【问题标题】:angular: write a service which mocks my real backend角度:编写一个模拟我真实后端的服务
【发布时间】:2014-10-21 01:03:05
【问题描述】:

我需要编写访问后端数据的代码。

问题是后端还没有准备好。所以我想注入一个服务,它可能通过配置使用真正的后端或模拟对象。

我认为角度服务是我所需要的。但我不清楚如何实现这一点。

app.factory('myService', function() {
  var mySrv;

  //if backend is live, get the data from there with $http
  //else get data from a mock json object
  return mySrv;
});

不知何故,我想我必须再编写两个服务,一个真正的一个和一个假的,然后在“myService”中调用一个或另一个?

也许我完全误解了模拟,但我不希望它被模拟用于测试运行(不适用于像这篇文章中的单元测试:Injecting a mock into an AngularJS service - 我希望应用程序真正使用我的模拟进行演示和开发目的。

【问题讨论】:

    标签: angularjs dependency-injection angularjs-service


    【解决方案1】:

    这实际上是 Angular 的依赖注入系统真正派上用场的地方。 在某种程度上,Angular 中的一切基本上都是provider 服务和工厂等方法只是避免样板代码的便利功能。

    可以在引导过程中配置提供程序,这对于设置与您描述的完全一样的场景非常方便。

    在最简单的情况下,provider 只需要是一个构造函数,它使用 $get 函数创建一个对象。 $get 是创建实际服务的地方,您可以在这里查看要创建的服务。

    //A simple provider
    function DataServiceProvider(){
    
      var _this = this;
    
      _this.$get = function(){
        //Use configured value to decide which
        // service to return
        return _this.useMock ? 
                 new MockService() : 
                 new RealService;
      };
    
    }
    

    现在您可以将其注册为应用程序模块的提供程序。

    angular.module('my-module', [])
      .provider('dataService', DataServiceProvider);
    

    并且提供者可以在创建第一个服务实例之前进行配置。 按照惯例,提供者的身份为NAME + 'Provider'

    angular.module('my-module')
      .config(['dataServiceProvider', function(dataServiceProvider){
        //Set the flag to use mock service
        dataServiceProvider.useMock = true;
      }]);
    

    现在,每当您在应用程序的任何位置注入 dataService 时,它都会使用您根据配置提供的模拟服务。

    您可以在下面的 sn-p 中看到一个完整的工作示例

    (function(){
    
      function RealService(){
        this.description = 'I\'m the real McCoy!';
      }
      
      function MockService(){
        this.description = 'I\'m a shady imposter :P';
      }
      
      function DataServiceProvider(){
        var $this = this;
        
        $this.useMock = false;
        
        $this.$get = function(){
          return $this.useMock ?
              new MockService() :
              new RealService();
        };
      }
      
      function CommonController(dataService){
        this.dataServiceDescription = dataService.description;
      }
      CommonController.$inject = ['dataService'];
      
      angular.module('common', [])
        .provider('dataService', DataServiceProvider)
        .controller('commonCtrl', CommonController);
      
      angular.module('provider-app-real-service', ['common'])
        .config(['dataServiceProvider', function(dataServiceProvider){
          dataServiceProvider.useMock = false;
        }]);
      
      angular.module('provider-app-mock-service', ['common'])
        .config(['dataServiceProvider', function(dataServiceProvider){
          dataServiceProvider.useMock = true;
        }]);
      
      
      var moduleNames = ['provider-app-real-service','provider-app-mock-service'];
        
      angular.forEach(moduleNames, function(modName){
        //Have to manually bootstrap because Angular only does one by default
        angular.bootstrap(document.getElementById(modName),[modName]);
      }); 
      
    }());
    <script src="http://code.angularjs.org/1.3.0/angular.js"></script>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" />
    
    <div class="container">
      <div class="row" id="provider-app-real-service">
        <div class="col-sm-12" ng-controller="commonCtrl as ctrl">
          <h1>{{ctrl.dataServiceDescription}}</h1>
        </div>
      </div>
      <div class="row" id="provider-app-mock-service">
        <div class="col-sm-12" ng-controller="commonCtrl as ctrl">
          <h1>{{ctrl.dataServiceDescription}}</h1>
        </div>
      </div>
    </div>

    【讨论】:

    • 这看起来很像我正在寻找的东西。我将仔细阅读您的详细答案以了解它,然后可能会接受它。谢谢!
    • 试想一下,您必须为应用程序中需要模拟的每项服务执行此操作。你会到处重复同样的事情。每个开发人员都需要了解这种随条件更新的反模式。您可以轻松地将其与语法糖和自动模拟联系起来。用 if else 创建实例......不是那么令人印象深刻的恕我直言。但这会带来一些维护上的麻烦..
    • stackoverflow.com/questions/25537396/… 。我也需要类似的东西,但我可以到达这里。从来没有机会调查我面临的具体问题。尽管它在我的应用程序中运行良好,大约有 30 多种数据服务:) 我也期待以一种非常简洁的方法更新这个答案,或者这个问题的任何其他答案也可能对我有帮助。 :)
    • @PSL - 如果您只关心一项服务,我认为这不是一种反模式。您的问题非常不同,因为您正在尝试更改整个应用程序的工作方式。这当然是一个崇高的目标,但我可能会考虑编写一个 HttpInterceptor 来使用模拟数据,而不是尝试模拟每个服务。此外,模块排序和注入器的问题是我之前写过的:technofattie.com/2013/04/12/…
    • @PSL - 我一直在考虑这个问题,并且对解决问题的好方法很感兴趣。我不介意谈论更多。我认为可能有一种方法可以选择创建注入器并以某种方式插入mocks 模块以覆盖现有组件,但我还不能 100% 确定如何。需要深入研究 Angular 源代码。我认为该解决方案对很多人都有用:)
    【解决方案2】:

    这需要成为一项服务吗?如果你想创建一个模拟服务,那么上面 Josh 的回答是完美的。

    如果您不依赖于使用服务,那么我建议您查看我对以下问题 Mock backend for Angular / Gulp app 的回答,该问题也与模拟后端有关。无论您的后端是创建还是不模拟它,都可以实现更稳定的测试运行和应用程序开发。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-01
      • 2020-06-24
      • 2020-09-21
      • 1970-01-01
      • 1970-01-01
      • 2016-07-08
      • 1970-01-01
      相关资源
      最近更新 更多