久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

使用 success() 和 error() 測試控制器

Test a controller with success() and error ()(使用 success() 和 error() 測試控制器)
本文介紹了使用 success() 和 error() 測試控制器的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧!

問題描述

限時送ChatGPT賬號..

我正在嘗試找出在控制器中單元測試成功和錯誤回調(diào)的最佳方法.我可以模擬出服務(wù)方法,只要控制器只使用默認(rèn)的 $q 函數(shù),例如then"(參見下面的示例).當(dāng)控制器響應(yīng)成功"或錯誤"承諾時,我遇到了問題.(對不起,如果我的術(shù)語不正確).

I'm trying to work out the best way to unit test success and error callbacks in controllers. I am able to mock out service methods, as long as the controller only uses the default $q functions such as 'then' (see the example below). I'm having an issue when the controller responds to a 'success' or 'error' promise. (Sorry if my terminology is not correct).

這是一個示例控制器服務(wù)

Here is an example controller service

var myControllers = angular.module('myControllers');

myControllers.controller('SimpleController', ['$scope', 'myService',
  function ($scope, myService) {

      var id = 1;
      $scope.loadData = function () {
          myService.get(id).then(function (response) {
              $scope.data = response.data;
          });
      };

      $scope.loadData2 = function () {
          myService.get(id).success(function (response) {
              $scope.data = response.data;
          }).error(function(response) {
              $scope.error = 'ERROR';
          });
      }; 
  }]);


cocoApp.service('myService', [
    '$http', function($http) {
        function get(id) {
            return $http.get('/api/' + id);
        }
    }
]);  

我有以下測試

'use strict';

describe('SimpleControllerTests', function () {

    var scope;
    var controller;
    var getResponse = { data: 'this is a mocked response' };

    beforeEach(angular.mock.module('myApp'));

    beforeEach(angular.mock.inject(function($q, $controller, $rootScope, $routeParams){

        scope = $rootScope;
        var myServiceMock = {
            get: function() {}
        };

        // setup a promise for the get
        var getDeferred = $q.defer();
        getDeferred.resolve(getResponse);
        spyOn(myServiceMock, 'get').andReturn(getDeferred.promise);

        controller = $controller('SimpleController', { $scope: scope, myService: myServiceMock });
    }));


    it('this tests works', function() {
        scope.loadData();
        expect(scope.data).toEqual(getResponse.data);
    });

    it('this doesnt work', function () {
        scope.loadData2();
        expect(scope.data).toEqual(getResponse.data);
    });
});

第一個測試通過,第二個測試失敗,出現(xiàn)錯誤TypeError: Object does not support property or method 'success'".在這種情況下,我得到了 getDeferred.promise沒有成功功能.好的,這是一個問題,編寫此測試的好方法是什么,以便我可以測試成功"、錯誤"和模擬服務(wù)的那么"條件?

The first test passes and the second fails with the error "TypeError: Object doesn't support property or method 'success'". I get that in this instance that getDeferred.promise does not have a success function. Okay here is the question, what is a nice way to write this test so that I can test the 'success', 'error' & 'then' conditions of a mocked service ?

我開始認(rèn)為我應(yīng)該避免在我的控制器中使用 success() 和 error()...

I'm starting to think that I should avoid the use of success() and error() in my controllers...

編輯

所以在考慮了更多之后,并且感謝下面的詳細(xì)答案,我得出結(jié)論,在控制器中處理成功和錯誤回調(diào)是不好的. 正如 HackedByChinese 提到的在successerror 下面是$http 添加的語法糖.因此,實際上,通過嘗試處理成功錯誤,我讓 $http 問題泄漏到我的控制器中,這正是我試圖通過將 $http 調(diào)用包裝在服務(wù)中來避免的.我要采取的方法是把控制器改成不使用successerror:

So after thinking about this some more, and thanks to the detailed answer below, I've come to the conclusion that the handling the success and error callbacks in the controller is bad. As HackedByChinese mentions below successerror is syntactic sugar that is added by $http. So, in actual fact, by trying to handle success error I am letting $http concerns leak into my controller, which is exactly what I was trying to avoid by wrapping the $http calls in a service. The approach I'm going to take is to change the controller not to use success error:

myControllers.controller('SimpleController', ['$scope', 'myService',
  function ($scope, myService) {

      var id = 1;
      $scope.loadData = function () {
          myService.get(id).then(function (response) {
              $scope.data = response.data;
          }, function (response) {
              $scope.error = 'ERROR';
          });
      };
  }]);

這樣我可以通過在延遲對象上調(diào)用resolve()和reject()來測試錯誤成功條件:

This way I can test the error success conditions by calling resolve() and reject() on the deferred object:

'use strict';

describe('SimpleControllerTests', function () {

    var scope;
    var controller;
    var getResponse = { data: 'this is a mocked response' };
    var getDeferred;
    var myServiceMock;

    //mock Application to allow us to inject our own dependencies
    beforeEach(angular.mock.module('myApp'));
    //mock the controller for the same reason and include $rootScope and $controller
    beforeEach(angular.mock.inject(function($q, $controller, $rootScope, $routeParams) {

        scope = $rootScope;
        myServiceMock = {
            get: function() {}
        };
        // setup a promise for the get
        getDeferred = $q.defer();
        spyOn(myServiceMock, 'get').andReturn(getDeferred.promise);
        controller = $controller('SimpleController', { $scope: scope, myService: myServiceMock });  
    }));

    it('should set some data on the scope when successful', function () {
        getDeferred.resolve(getResponse);
        scope.loadData();
        scope.$apply();
        expect(myServiceMock.get).toHaveBeenCalled();
        expect(scope.data).toEqual(getResponse.data);
    });

    it('should do something else when unsuccessful', function () {
        getDeferred.reject(getResponse);
        scope.loadData();
        scope.$apply();
        expect(myServiceMock.get).toHaveBeenCalled();
        expect(scope.error).toEqual('ERROR');
    });
});

推薦答案

正如有人在刪除的答案中提到的,successerror$http 所以當(dāng)你創(chuàng)建自己的 Promise 時它們不存在.你有兩個選擇:

As someone had mentioned in a deleted answer, success and error are syntactic sugar added by $http so they aren't there when you create your own promise. You have two options:

這個想法是讓您的 myService 在不知道它正在被測試的情況下像往常一樣運行.$httpBackend 將讓您設(shè)置期望和響應(yīng),并刷新它們,以便您可以同步完成測試.$http 不會更明智,它返回的承諾看起來和功能就像一個真實的承諾.如果您有對 HTTP 期望很少的簡單測試,則此選項很好.

The idea is to let your myService act like it normally would without knowing it's being tested. $httpBackend will let you set up expectations and responses, and flush them so you can complete your tests synchronously. $http won't be any wiser and the promise it returns will look and function like a real one. This option is good if you have simple tests with few HTTP expectations.

'use strict';

describe('SimpleControllerTests', function () {

    var scope;
    var expectedResponse = { name: 'this is a mocked response' };
    var $httpBackend, $controller;

    beforeEach(module('myApp'));

    beforeEach(inject(function(_$rootScope_, _$controller_, _$httpBackend_){ 
        // the underscores are a convention ng understands, just helps us differentiate parameters from variables
        $controller = _$controller_;
        $httpBackend = _$httpBackend_;
        scope = _$rootScope_;
    }));

    // makes sure all expected requests are made by the time the test ends
    afterEach(function() {
      $httpBackend.verifyNoOutstandingExpectation();
      $httpBackend.verifyNoOutstandingRequest();
    });

    describe('should load data successfully', function() {

        beforeEach(function() {
           $httpBackend.expectGET('/api/1').response(expectedResponse);
           $controller('SimpleController', { $scope: scope });

           // causes the http requests which will be issued by myService to be completed synchronously, and thus will process the fake response we defined above with the expectGET
           $httpBackend.flush();
        });

        it('using loadData()', function() {
          scope.loadData();
          expect(scope.data).toEqual(expectedResponse);
        });

        it('using loadData2()', function () {
          scope.loadData2();
          expect(scope.data).toEqual(expectedResponse);
        });
    });

    describe('should fail to load data', function() {
        beforeEach(function() {
           $httpBackend.expectGET('/api/1').response(500); // return 500 - Server Error
           $controller('SimpleController', { $scope: scope });
           $httpBackend.flush();
        });

        it('using loadData()', function() {
          scope.loadData();
          expect(scope.error).toEqual('ERROR');
        });

        it('using loadData2()', function () {
          scope.loadData2();
          expect(scope.error).toEqual('ERROR');
        });
    });           
});

2 - 返回一個完全模擬的承諾

如果您正在測試的事物具有復(fù)雜的依賴關(guān)系并且所有設(shè)置都令人頭疼,那么您可能仍想像您嘗試的那樣模擬服務(wù)和調(diào)用本身.不同之處在于您需要完全模擬 promise.這樣做的缺點可能是創(chuàng)建所有可能的模擬 Promise,但是您可以通過創(chuàng)建自己的函數(shù)來創(chuàng)建這些對象來簡化它.

2 - Return a fully-mocked promise

If the thing you're testing has complicated dependencies and all the set-up is a headache, you may still want to mock the services and the calls themselves as you have attempted. The difference is that you'll want to fully mock promise. The downside of this can be creating all the possible mock promises, however you could make that easier by creating your own function for creating these objects.

之所以如此,是因為我們假裝它通過立即調(diào)用 successerrorthen 提供的處理程序來解決,導(dǎo)致同步完成.

The reason this works is because we pretend that it resolves by invoking the handlers provided by success, error, or then immediately, causing it to complete synchronously.

'use strict';

describe('SimpleControllerTests', function () {

    var scope;
    var expectedResponse = { name: 'this is a mocked response' };
    var $controller, _mockMyService, _mockPromise = null;

    beforeEach(module('myApp'));

    beforeEach(inject(function(_$rootScope_, _$controller_){ 
        $controller = _$controller_;
        scope = _$rootScope_;

        _mockMyService = {
            get: function() {
               return _mockPromise;
            }
        };
    }));

    describe('should load data successfully', function() {

        beforeEach(function() {

          _mockPromise = {
             then: function(successFn) {
               successFn(expectedResponse);
             },
             success: function(fn) {
               fn(expectedResponse);
             }
          };

           $controller('SimpleController', { $scope: scope, myService: _mockMyService });
        });

        it('using loadData()', function() {
          scope.loadData();
          expect(scope.data).toEqual(expectedResponse);
        });

        it('using loadData2()', function () {
          scope.loadData2();
          expect(scope.data).toEqual(expectedResponse);
        });
    });

    describe('should fail to load data', function() {
        beforeEach(function() {
          _mockPromise = {
            then: function(successFn, errorFn) {
              errorFn();
            },
            error: function(fn) {
              fn();
            }
          };

          $controller('SimpleController', { $scope: scope, myService: _mockMyService });
        });

        it('using loadData()', function() {
          scope.loadData();
          expect(scope.error).toEqual("ERROR");
        });

        it('using loadData2()', function () {
          scope.loadData2();
          expect(scope.error).toEqual("ERROR");
        });
    });           
});

即使在大型應(yīng)用程序中,我也很少選擇選項 2.

I rarely go for option 2, even in big applications.

不管怎樣,您的 loadDataloadData2 http 處理程序都有錯誤.他們引用 response.data 但 handlers 將被解析直接響應(yīng)數(shù)據(jù),而不是響應(yīng)對象(所以它應(yīng)該是 data 而不是 response.data).

For what it's worth, your loadData and loadData2 http handlers have an error. They reference response.data but the handlers will be called with the parsed response data directly, not the response object (so it should be data instead of response.data).

這篇關(guān)于使用 success() 和 error() 測試控制器的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

【網(wǎng)站聲明】本站部分內(nèi)容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請聯(lián)系我們刪除處理,感謝您的支持!

相關(guān)文檔推薦

How can I get my jasmine tests fixtures to load before the javascript considers the document to be quot;readyquot;?(在 javascript 認(rèn)為文檔“準(zhǔn)備好之前,如何讓我的 jasmine 測試裝置加載?) - IT屋-程序員軟件開發(fā)技術(shù)
What do jasmine runs and waitsFor actually do?(jasmine 運行和等待實際上是做什么的?)
How to provide mock files to change event of lt;input type=#39;file#39;gt; for unit testing(如何提供模擬文件來更改 lt;input type=filegt; 的事件用于單元測試)
How to unit test a chained method using Jasmine(如何使用 Jasmine 對鏈?zhǔn)椒椒ㄟM行單元測試)
How do I inject $rootScope into an AngularJS unit test?(如何將 $rootScope 注入 AngularJS 單元測試?)
Jasmine - How to spy on a function call within a function?(Jasmine - 如何監(jiān)視函數(shù)中的函數(shù)調(diào)用?)
主站蜘蛛池模板: 欧美日韩1区2区3区 欧美久久一区 | 一级女毛片| 国产黑丝av| 国产亚洲精品精品国产亚洲综合 | 成年人黄色一级毛片 | 亚洲国产一区二区视频 | 青青草原精品99久久精品66 | 久久国产精品一区二区三区 | 亚洲精品在线视频 | 国产在线观看网站 | 久久久亚洲一区 | 久久久久国产 | 毛片一区二区三区 | 亚洲成av人影片在线观看 | 91精品久久久久久综合五月天 | 亚洲精品一区二三区不卡 | 国产精品久久久久久久久久免费看 | 不卡av电影在线播放 | 久久国产精品一区二区 | 欧美一区二区三区小说 | 日韩在线免费 | 久久成人一区二区三区 | 免费看黄视频网站 | 日韩av在线一区二区三区 | 成人在线免费电影 | 成人国产精品久久久 | 日本久久www成人免 成人久久久久 | 一区二区在线免费观看视频 | 成人一区二区三区 | 美女毛片免费看 | 国产精品久久久久久久久久 | 国产欧美一区二区三区免费 | 亚洲精品区 | 免费精品视频 | 久久国产成人精品国产成人亚洲 | 精品乱码一区二区 | 中文在线视频观看 | 午夜伦理影院 | 国产精品美女久久久久aⅴ国产馆 | 国产高清在线精品 | 精品一区二区三区中文字幕 |