অ্যাঙ্গুলারজেএস জেসমিন ইউনিট পরীক্ষায় প্রতিশ্রুতি প্রদান করে এমন একটি পরিষেবা আমি কীভাবে উপহাস করব?


152

আমার কাছে myServiceসেগুলি ব্যবহার রয়েছে myOtherService, যা প্রত্যন্ত কল করে, প্রতিশ্রুতি ফেরায়:

angular.module('app.myService', ['app.myOtherService'])
  .factory('myService', [
    myOtherService,
    function(myOtherService) {
      function makeRemoteCall() {
        return myOtherService.makeRemoteCallReturningPromise();
      }

      return {
        makeRemoteCall: makeRemoteCall
      };      
    }
  ])

আমার জন্য একক পরীক্ষা করার জন্য myServiceআমার উপহাস করা দরকার myOtherService, এর makeRemoteCallReturningPromiseপদ্ধতিটি প্রতিশ্রুতি দেয় returns আমি এটি এইভাবে করি:

describe('Testing remote call returning promise', function() {
  var myService;
  var myOtherServiceMock = {};

  beforeEach(module('app.myService'));

  // I have to inject mock when calling module(),
  // and module() should come before any inject()
  beforeEach(module(function ($provide) {
    $provide.value('myOtherService', myOtherServiceMock);
  }));

  // However, in order to properly construct my mock
  // I need $q, which can give me a promise
  beforeEach(inject(function(_myService_, $q){
    myService = _myService_;
    myOtherServiceMock = {
      makeRemoteCallReturningPromise: function() {
        var deferred = $q.defer();

        deferred.resolve('Remote call result');

        return deferred.promise;
      }    
    };
  }

  // Here the value of myOtherServiceMock is not
  // updated, and it is still {}
  it('can do remote call', inject(function() {
    myService.makeRemoteCall() // Error: makeRemoteCall() is not defined on {}
      .then(function() {
        console.log('Success');
      });    
  }));  

উপরের দিক থেকে আপনি দেখতে পাচ্ছেন, আমার উপহাসের সংজ্ঞা নির্ভর করে $q, যা আমাকে ব্যবহার করে লোড করতে হবে inject()। তদ্ব্যতীত, মোককে ইনজেকশন দেওয়ার ঘটনাটি ঘটতে module()হবে যা আগে আসা উচিত inject()। তবে, আমি একবার এটি পরিবর্তন করার পরে মোকটির মানটি আপডেট হয় না।

এটি করার উপযুক্ত উপায় কী?


ত্রুটিটি কি আসলেই চালু আছে myService.makeRemoteCall()? যদি তা হয় তবে সমস্যাটি হ'ল myServiceনা হওয়া নিয়ে makeRemoteCall, আপনার উপহাসের সাথে কিছুই করার নয় myOtherService
dnc253

ত্রুটিটি মাই সার্ভিস.মেকরেমোটক্যাল () এ রয়েছে, কারণ মাই সার্ভিস.মিআউটার সার্ভিসেস এই মুহুর্তে কেবল একটি খালি অবজেক্ট (এর মানটি কৌণিক দ্বারা কখনই আপডেট করা হয়নি)
জর্জিই ওলেইনিকভ

আপনি খালি বস্তুটি আইওকে ধারকটিতে যুক্ত করুন, তারপরে আপনি রেফারেন্সটি মাইওথার সার্ভিসমক পরিবর্তন করে একটি নতুন অবজেক্টের দিকে নির্দেশ করুন যা আপনি গুপ্তচরিত করেছেন। আইওসি পাত্রে যা রয়েছে তা প্রতিফলিত হওয়ার সাথে সাথে তা প্রতিফলিত হয়।
twDuke

উত্তর:


175

আমি নিশ্চিত না যে আপনি যেভাবে এটি করেছিলেন তা কার্যকর হয় না তবে আমি সাধারণত এটি spyOnফাংশন দিয়েই করি। এটার মতো কিছু:

describe('Testing remote call returning promise', function() {
  var myService;

  beforeEach(module('app.myService'));

  beforeEach(inject( function(_myService_, myOtherService, $q){
    myService = _myService_;
    spyOn(myOtherService, "makeRemoteCallReturningPromise").and.callFake(function() {
        var deferred = $q.defer();
        deferred.resolve('Remote call result');
        return deferred.promise;
    });
  }

  it('can do remote call', inject(function() {
    myService.makeRemoteCall()
      .then(function() {
        console.log('Success');
      });    
  }));

এছাড়াও মনে রাখবেন যে ফাংশনটি $digestকল করার জন্য আপনাকে একটি কল thenকরতে হবে। $ Q ডকুমেন্টেশনের পরীক্ষার বিভাগটি দেখুন ।

------ সম্পাদনা ------

আপনি কী করছেন তা ঘনিষ্ঠভাবে দেখার পরে, আমি মনে করি যে আমি আপনার কোডটিতে সমস্যাটি দেখতে পাচ্ছি। ইন beforeEach, আপনি myOtherServiceMockসম্পূর্ণ নতুন অবজেক্টে সেট করছেন । $provideএই রেফারেন্স দেখতে হবে না। আপনাকে কেবল বিদ্যমান রেফারেন্সটি আপডেট করতে হবে:

beforeEach(inject( function(_myService_, $q){
    myService = _myService_;
    myOtherServiceMock.makeRemoteCallReturningPromise = function() {
        var deferred = $q.defer();
        deferred.resolve('Remote call result');
        return deferred.promise;   
    };
  }

1
এবং আপনি গতকাল আমাকে ফলাফল প্রকাশ না করে হত্যা করেছেন। এবং কলফেক () এর সুন্দর প্রদর্শন। ধন্যবাদ.
প্রিয়া রঞ্জন সিং

পরিবর্তে andCallFakeআপনি ব্যবহার করতে পারেন andReturnValue(deferred.promise)(বা and.returnValue(deferred.promise)জেসমিন ২.০+ এ)। অবশ্যই deferredফোন করার আগে আপনাকে spyOnঅবশ্যই সংজ্ঞা দেওয়া দরকার ।
জর্দান

1
আপনার $digestযদি সুযোগের অ্যাক্সেস না থাকে আপনি কীভাবে এই ক্ষেত্রে কল করবেন?
জিম আহো

7
@ জিমআহহো সাধারণত আপনি কেবল ইনজেকশন করেন $rootScopeএবং এটিকে কল $digestকরেন।
dnc253

1
এই ক্ষেত্রে পিছিয়ে ব্যবহার করা অপ্রয়োজনীয়। আপনি কেবল $q.when() codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrong
fodma1

69

আমরা গুপ্তচর দ্বারা সরাসরি জেসমিনের প্রতিশ্রুতি বাস্তবায়নের প্রয়োগটিও লিখতে পারি।

spyOn(myOtherService, "makeRemoteCallReturningPromise").andReturn($q.when({}));

জুঁই 2 এর জন্য:

spyOn(myOtherService, "makeRemoteCallReturningPromise").and.returnValue($q.when({}));

(মন্তব্য থেকে অনুলিপি, ccnokes ধন্যবাদ)


12
জেসমিন ২.০, .আর রিটারন () ব্যবহার করে লোকেদের কাছে দ্রষ্টব্য .and.returnValue দ্বারা প্রতিস্থাপন করা হয়েছে। উপরের উদাহরণটি হ'ল: spyOn(myOtherService, "makeRemoteCallReturningPromise").and.returnValue($q.when({}));আমি আধা ঘন্টা খালি মেরে ফেলেছি।
সিএনএনোকস

13
describe('testing a method() on a service', function () {    

    var mock, service

    function init(){
         return angular.mock.inject(function ($injector,, _serviceUnderTest_) {
                mock = $injector.get('service_that_is_being_mocked');;                    
                service = __serviceUnderTest_;
            });
    }

    beforeEach(module('yourApp'));
    beforeEach(init());

    it('that has a then', function () {
       //arrange                   
        var spy= spyOn(mock, 'actionBeingCalled').and.callFake(function () {
            return {
                then: function (callback) {
                    return callback({'foo' : "bar"});
                }
            };
        });

        //act                
        var result = service.actionUnderTest(); // does cleverness

        //assert 
        expect(spy).toHaveBeenCalled();  
    });
});

1
অতীতে আমি এইভাবেই করেছি। এমন একটি গুপ্তচর তৈরি করুন যা একটি নকল ফেরত দেয় যা "তখন" নকল করে
ড্যারেন কর্পেট

আপনি যে সম্পূর্ণ পরীক্ষাটি করেছেন তার উদাহরণ দিতে পারেন an আমার কোনও পরিষেবা থাকার ক্ষেত্রে একই রকম সমস্যা রয়েছে যা প্রতিশ্রুতি ফেরায়, তবে এটির সাথে একটি কলও আসে যা প্রতিশ্রুতি দেয়!
রব প্যাডক

হাই রব, নিশ্চিত নন যে আপনি কেন কোনও কলকে মক করতে চান যা একটি মক অন্য পরিষেবাতে তোলে তা অবশ্যই আপনি সেই পরীক্ষাটি পরীক্ষা করতে চান testing ফাংশনটি পরীক্ষা করার সময়। যদি ফাংশন কল করে আপনি কল করে যাচ্ছেন কোনও পরিষেবা একটি ডেটা হয়ে যায় তবে আপনার উপহাসের প্রতিশ্রুতি কোনও নকল প্রভাবিত ডেটা সেট ফিরিয়ে দেবে সেই ডেটার ক্ষতি করে, কমপক্ষে আমি এটি করব।
ড্যারেন কর্পেট

আমি এই পথটি শুরু করেছি এবং এটি সাধারণ দৃশ্যের জন্য দুর্দান্ত কাজ করে। এমনকি আমি এমন একটি মক তৈরি করেছি যা শৃঙ্খলা অনুকরণ করে এবং চেইনটি gist.github.com/marknadig/c3e8f2d3fff9d22da42b চেক করার জন্য " কিপ " / "ব্রেক" সহায়তাকারীদের সরবরাহ করে তবে আরও জটিল পরিস্থিতিতে, এটি তবে নীচে নেমে আসে। আমার ক্ষেত্রে, আমার একটি পরিষেবা ছিল যা শর্তাধীন একটি ক্যাশে (ডাব্লু / স্থগিত) থেকে আইটেমগুলি ফিরিয়ে দেয় বা একটি অনুরোধ জানায়। সুতরাং, এটি নিজের প্রতিশ্রুতি তৈরি করছিল।
মার্ক নাদিগ


8

আপনি আপনার পরিষেবা উপহাস করার জন্য সিননের মতো স্টিবিং লাইব্রেরি ব্যবহার করতে পারেন। তারপরে আপনি আপনার প্রতিশ্রুতি হিসাবে $ q.wen () ফিরিয়ে দিতে পারবেন। যদি আপনার স্কোপ অবজেক্টের মান প্রতিশ্রুতি ফলাফল থেকে আসে তবে আপনাকে স্কোপ কল করতে হবে $ রুট $ ডাইজেস্ট ()।

var scope, controller, datacontextMock, customer;
  beforeEach(function () {
        module('app');
        inject(function ($rootScope, $controller,common, datacontext) {
            scope = $rootScope.$new();
            var $q = common.$q;
            datacontextMock = sinon.stub(datacontext);
            customer = {id:1};
           datacontextMock.customer.returns($q.when(customer));

            controller = $controller('Index', { $scope: scope });

        })
    });


    it('customer id to be 1.', function () {


            scope.$root.$digest();
            expect(controller.customer.id).toBe(1);


    });

2
$rootScope.$digest()প্রতিশ্রুতি সমাধান হওয়ার আহ্বান জানাতে এই নিখোঁজ টুকরোটি রয়েছে

2

ব্যবহার sinon:

const mockAction = sinon.stub(MyService.prototype,'actionBeingCalled')
                     .returns(httpPromise(200));

এটি জানা httpPromiseযায়:

const httpPromise = (code) => new Promise((resolve, reject) =>
  (code >= 200 && code <= 299) ? resolve({ code }) : reject({ code, error:true })
);

0

সত্যিই .. আপনি মডিউলের পরিবর্তে কোনও পরিষেবা উপহাস করার জন্য ইনজেকশনের উপর নির্ভর করে এই ভুল পথে চলে যাচ্ছেন। এছাড়াও, প্রত্যেকের আগে ইনজেকশন কল করা একটি অ্যান্টি-প্যাটার্ন কারণ এটি প্রতি পরীক্ষার ভিত্তিতে উপহাসকে কঠিন করে তোলে।

আমি এখানে এটি কীভাবে করব ...

module(function ($provide) {
  // By using a decorator we can access $q and stub our method with a promise.
  $provide.decorator('myOtherService', function ($delegate, $q) {

    $delegate.makeRemoteCallReturningPromise = function () {
      var dfd = $q.defer();
      dfd.resolve('some value');
      return dfd.promise;
    };
  });
});

এখন আপনি যখন নিজের পরিষেবাটি ইনজেক্ট করবেন তখন এটির ব্যবহারের জন্য সঠিকভাবে উপহাসের পদ্ধতি থাকবে method


3
প্রতিটি পূর্বের পুরো বিষয়টি হ'ল এটি প্রতিটি পরীক্ষার আগে বলা হয় আমি জানি না আপনি কীভাবে আপনার পরীক্ষা লিখেন তবে ব্যক্তিগতভাবে আমি একক ফাংশনের জন্য একাধিক পরীক্ষা লিখি, সুতরাং আমার একটি সাধারণ ভিত্তি স্থাপন করা হবে যা আগে ডাকা হত প্রতিটি পরীক্ষা। এটি সফ্টওয়্যার ইঞ্জিনিয়ারিংয়ের সাথে সংযুক্ত হওয়ার সাথে সাথে আপনি অ্যান্টি প্যাটার্নের বোঝার অর্থটিও সন্ধান করতে পারেন।
ড্যারেন কর্পেট

0

Sinon.stub () হিসাবে রিটার্ন হিসাবে ($ q.when ({})) হিসাবে আমি সেই দরকারী, ছুরিকাঘাতের পরিষেবা ফাংশনটি পেয়েছি:

this.myService = {
   myFunction: sinon.stub().returns( $q.when( {} ) )
};

this.scope = $rootScope.$new();
this.angularStubs = {
    myService: this.myService,
    $scope: this.scope
};
this.ctrl = $controller( require( 'app/bla/bla.controller' ), this.angularStubs );

নিয়ামক:

this.someMethod = function(someObj) {
   myService.myFunction( someObj ).then( function() {
        someObj.loaded = 'bla-bla';
   }, function() {
        // failure
   } );   
};

এবং পরীক্ষা

const obj = {
    field: 'value'
};
this.ctrl.someMethod( obj );

this.scope.$digest();

expect( this.myService.myFunction ).toHaveBeenCalled();
expect( obj.loaded ).toEqual( 'bla-bla' );

-1

কোড স্নিপেট:

spyOn(myOtherService, "makeRemoteCallReturningPromise").and.callFake(function() {
    var deferred = $q.defer();
    deferred.resolve('Remote call result');
    return deferred.promise;
});

আরও সংক্ষিপ্ত আকারে লেখা যেতে পারে:

spyOn(myOtherService, "makeRemoteCallReturningPromise").and.returnValue(function() {
    return $q.resolve('Remote call result');
});
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.