Menguji $scope di pengontrol AngularJs dengan ketergantungan pada $filter

Saya telah melalui beberapa tutorial dan contoh dasar tetapi saya mengalami kesulitan menulis unit test untuk pengontrol saya. Saya telah melihat cuplikan kode membuat instance pengontrol dan membiarkan sudut menyuntikkan objek $rootScope yang selanjutnya digunakan untuk membuat objek scope baru untuk pengontrol. Tapi saya tidak tahu kenapa ctrl.$scope? tidak ditentukan:

 describe('EmployeeCtrl', function () {
    var scope, ctrl, $httpBackend;

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller, $filter) {
        $httpBackend = _$httpBackend_;       

        scope = $rootScope.$new();
        ctrl = $controller('EmployeeCtrl', { $scope: scope});
        expect(ctrl).not.toBeUndefined();
        expect(scope).not.toBeUndefined();   //<-- PASS!      
        expect(ctrl.$scope).not.toBeUndefined();  //<-- FAIL!       
    }));
});

Saya akhirnya menggunakan variabel scope alih-alih ctrl.$scope tetapi kemudian pada pengujian pertama saya, saya tidak tahu cara menguji unit variabel fungsi di dalam pengontrol saya:

Pengontrol:

 function EmployeeCtrl($scope, $http, $filter, Employee) {
  var searchMatch = function (haystack, needle) {
   return false;
  }
 }

Pengujian unit rusak:

it('should search ', function () {                
    expect(ctrl.searchMatch('numbers','one')).toBe(false);
});

Inilah yang saya dapatkan

TypeError: Objek # tidak memiliki metode 'searchMatch'

Bagaimana Anda menguji fungsi itu? Sebagai solusinya, saya memindahkan metode saya ke $scope sehingga saya dapat menguji scope.searchMatch tetapi saya bertanya-tanya apakah ini satu-satunya cara.

Akhirnya, pada pengujian saya muncul $filter tidak terdefinisi juga, bagaimana cara menyuntikkannya? Saya mencoba ini tetapi tidak berhasil:

ctrl = $controller('EmployeeCtrl', { $scope: scope, $filter: $filter });

Terima kasih

Pembaruan: Metode yang disebutkan di atas untuk menyuntikkan $filter berfungsi dengan baik.


person Ulises    schedule 07.01.2013    source sumber
comment
tes melati saya putus pada metode inject. Itu tidak ditemukan. Apa yang saya lewatkan. sudut bukan nol. Saya memiliki tes yang lulus yang memverifikasi bahwa itu dimuat.   -  person Hcabnettek    schedule 22.03.2013


Jawaban (4)


Pemahaman saya adalah, di Angularjs, Anda meneruskan objek cakupan ke pengontrol saat aplikasi dimulai dan pengontrol mengubah cakupannya. Pengontrol tidak dipanggil lagi.

Apa yang sebenarnya dilakukan pengontrol, di Angularjs, adalah menginisialisasi cakupan: pengontrol hanya berjalan satu kali. Jika Anda memahami hal ini, Anda menyadari bahwa menanyakan ruang lingkup kepada pengontrol seperti ini:

currentScope = myController.scope;

tidak masuk akal.

(Kebetulan, salah satu hal yang saya tidak suka di Angular adalah nama yang mereka pilih. Jika yang dilakukan 'pengontrol' adalah menginisialisasi cakupan maka itu sebenarnya bukan pengontrol. Ada banyak hal seperti ini di Angular API).

Saya pikir cara yang 'tepat' untuk menguji 'pengontrol' adalah dengan membuat ruang lingkup kosong baru dari awal dalam klausa beforeEach Jasmine dan menggunakan 'pengontrol' untuk menginisialisasi a lingkup kosong baru seperti ini ::

var ctrl, myScope;

beforeEach(inject(function($controller, $rootScope) {
    myScope = $rootScope.$new();
    ctrl = $controller('myController', {
        $scope: myScope
    });
}));

Dan kemudian menguji cakupan yang baru dibuat memiliki properti yang diharapkan:

it('In the scope, the initial value for a=2', function() {
            expect(myScope.a).toBe(2);
});

Dengan kata lain, Anda tidak menguji pengontrolnya; Anda menguji cakupan yang telah dibuat pengontrol.

Jadi, Anda melakukannya dengan benar.

person Robert    schedule 11.01.2013
comment
Itu lebih masuk akal. Terima kasih banyak ! - person Ulises; 13.01.2013

Berikut pola lain yang mungkin lebih mudah diikuti:

var $scope;
beforeEach(module(function ($provide) {
  $scope = {
    // set anything you want here or nothing
  };
  $provide.value('$scope', $scope);
}));

var ctrl;
beforeEach(inject(function ($controller) {
  ctrl = $controller('MyController');
}));

it('should test something...', function () {
  // $scope will have any properties set by
  // the controller so you can now do asserts
  // on them.
});

Anda dapat menggunakan pola yang sama untuk menetapkan nilai $location dan $window serta lainnya.

person Guy    schedule 04.10.2014

Hanya ada dua kemungkinan:

Tambahkan searchMatch ke cakupan (seperti yang Anda sebutkan) atau

Kembalikan fungsi searchMatch:

function EmployeeCtrl($scope, $http, $filter, Employee) {
  return {
    searchMatch: function (haystack, needle) {
      return false;
    }
  };
 }

Jika memang harus dirahasiakan, maka Anda harus menguji fitur yang menggunakannya.

Untuk mendapatkan $filter, Anda dapat mencoba yang berikut ini:

var $filter = angular.injector(['ng']).get('$filter'); 
person asgoth    schedule 07.01.2013
comment
Terima kasih, dan bagaimana cara menyuntikkan $filter? - person Ulises; 08.01.2013
comment
Saya telah memperbarui jawaban saya. Coba dengan angle.injector(), yang mengembalikan objek $injector, yang berisi layanan sudut, seperti $filter, $controller, ... - person asgoth; 08.01.2013

Untuk menguji filter, lakukan hal berikut untuk mendapatkan filter target:

var ctrl, myScope, $filter;
beforeEach(inject(function(_$filter_){
    $filter = _$filter_;
}))

Jika nama filter Anda adalah AccountTimeZone, lakukan ini:

let accountTimeZoneFilter = $filter('AccountTimeZone');
person MING WU    schedule 24.05.2021