2012-02-09 16 views
31

तो मैं सिर्फ अपनी प्रगति जावास्क्रिप्ट अनुप्रयोग के लिए परीक्षण लिखने के लिए, का उपयोग कर sinon.js & jasmine.js शुरू कर दिया है। कुल मिलाकर अच्छी तरह से काम करता है, लेकिन मुझे अपने राउटर का परीक्षण करने में भी सक्षम होना चाहिए।backbone.js में सही राउटर परीक्षण कर रहे हैं?

राउटर, अपनी वर्तमान स्थिति में, विचारों और अन्य सामग्री की एक संख्या को गति प्रदान करेगा आवेदन राज्य और यूआई itneraction पर निर्भर लागू करके वर्तमान jasmine.js परीक्षण समाप्त।

तो मैं कैसे परीक्षण कर सकते हैं कि अलग-अलग स्थानों के लिए मार्ग काम करेगा, राउटर "सैंडबॉक्स" और अनुमति देने के लिए उन्हें मार्ग बदलने के लिए नहीं रखते हुए?

क्या मैं कुछ प्रकार का नकली फ़ंक्शन सेट कर सकता हूं जो पुशस्टेट परिवर्तनों या इसी तरह की निगरानी करेगा?

+0

बाउंटी चालू है! इस – Industrial

उत्तर

4

यहां मैं अपने आप का उपयोग करके समाप्त हुआ।मैं इसे विस्तार और यह किसी भी आगे तर्क लागू करने से रोकने के लिए एक खाली विधि के साथ तरीकों अधिभावी जब बुलाया जा रहा द्वारा रूटर के एक नकली संस्करण बनाया:

describe("routers/main", function() { 

    beforeEach(function() { 

     // Create a mock version of our router by extending it and only overriding 
     // the methods 
     var mockRouter = App.Routers["Main"].extend({ 
      index: function() {}, 
      login: function() {}, 
      logoff: function() {} 
     }); 

     // Set up a spy and invoke the router 
     this.routeSpy = sinon.spy(); 
     this.router = new mockRouter; 

     // Prevent history.start from throwing error 
     try { 
      Backbone.history.start({silent:true, pushState:true}); 
     } catch(e) { 

     } 

     // Reset URL 
     this.router.navigate("tests/SpecRunner.html"); 
    }); 

    afterEach(function(){ 
     // Reset URL 
     this.router.navigate("tests/SpecRunner.html"); 
    }); 

    it('Has the right amount of routes', function() { 
     expect(_.size(this.router.routes)).toEqual(4); 
    }); 

    it('/ -route exists and points to the right method', function() { 
     expect(this.router.routes['']).toEqual('index'); 
    }); 

    it("Can navigate to /", function() { 
     this.router.bind("route:index", this.routeSpy); 
     this.router.navigate("", true); 
     expect(this.routeSpy.calledOnce).toBeTruthy(); 
     expect(this.routeSpy.calledWith()).toBeTruthy(); 
    }); 

}); 

ध्यान दें कि sinon.js जासूस बनाने के लिए ऊपर प्रयोग किया जाता है, साथ के साथ size फ़ंक्शन प्रदान करने के लिए।

+0

मुझे पता है कि यह एक पुराना सवाल है, लेकिन यह Google परिणामों में बहुत अधिक है, और मुझे लगता है कि लोग बेहतर कर सकते हैं। नीचे मेरा जवाब देखें। –

1

आप Backbone.Router.route उपहास करने के लिए समारोह है कि आंतरिक रूप से Backbone.History करने पर कार्यों बाध्य करने के लिए प्रयोग किया जाता है जो की है।

route : function(route, name, callback) { 
    Backbone.history || (Backbone.history = new Backbone.History); 
    if (!_.isRegExp(route)) route = this._routeToRegExp(route); 
    Backbone.history.route(route, _.bind(function(fragment) { 
    var args = this._extractParameters(route, fragment); 
    callback.apply(this, args); 
    this.trigger.apply(this, ['route:' + name].concat(args)); 
    }, this)); 
} 

आप कुछ इस तरह कर सकते, जो केवल कार्यों कॉल जब रूटर प्रारंभ हो जाएगा:

Backbone.Router.route = function(route, name, callback) { 
    callback(); 
} 

तुम भी एक में कॉलबैक बचा सकता है

मूल कार्य यही

ऑब्जेक्ट और नाम के रूप में मार्ग के साथ और चरण के अनुसार एक ही चरण पर कॉल करें:

var map = {} 
Backbone.Router.route = function(route, name, callback) { 
    map[route] = callback(); 
} 

for(i in map){ 
    map[i](); 
} 
+0

हाय एंड्रियास पर अधिक विचारों की प्रतीक्षा कर रहे हैं। अभी भी यह आपके कोड के साथ काम नहीं कर सकता है - राउटर विधि के अंदर तर्क अभी भी – Industrial

2
+0

धन्यवाद नहीं है। पहले से ही यह देखा है, लेकिन यह मुझे इस तथ्य को पाने में मदद नहीं करेगा कि मेरे राउटर पुनर्निर्देशन का आह्वान करते हैं और ... – Industrial

37

यहाँ परीक्षण है कि pushState अपेक्षा के अनुरूप काम करता है, चमेली के साथ इसे करने का एक कम levelish रास्ता है और वह है अपने राउटर को चीजें ठीक से ... सेट: 0 परीक्षण रीढ़ की हड्डी के बारे में एक बहुत अच्छा ट्यूटोरियल है मुझे लगता है कि router शुरू किया गया है और घर मार्ग मैप किया गया है। आप इसे अपने अन्य मार्गों के लिए अनुकूलित कर सकते हैं। मैं यह भी मान लें कि आपको अपने ऐप प्रारंभ में किए गए इस कार्य Backbone.history.start({ pushState: true });

describe('app.Router', function() { 

     var router = app.router, pushStateSpy; 

     it('has a "home" route', function() { 
      expect(router.routes['']).toEqual('home'); 
     }); 

     it('triggers the "home" route', function() { 
      var home = spyOn(router, 'home').andCallThrough(); 
      pushStateSpy = spyOn(window.history, 'pushState').andCallFake(function (data, title, url) { 
       expect(url).toEqual('/'); 
       router.home(); 
      }); 
      router.navigate(''); 
      expect(pushStateSpy).toHaveBeenCalled(); 
      expect(home).toHaveBeenCalled(); 
      ... 
     }); 
    }); 

आप को प्रभावी ढंग से Backbone.history.stop(); यह इस कारण के लिए मतलब है ऐसा करके इसी तरह की बातों को प्राप्त कर सकते हैं।

अद्यतन: ब्राउज़र्स कोई pushState साथ:

निश्चित रूप से

यह ठीक कार्य करेगा जब आप पर परीक्षण आपके ब्राउज़र pushState के लिए समर्थन हासिल है। आप ब्राउज़रों कि नहीं है के खिलाफ परीक्षण, तो आप सशर्त इस प्रकार का परीक्षण कर सकते हैं:

it('triggers the "home" route', function() { 
    var home = spyOn(router, 'home').andCallThrough(); 

    if (Backbone.history._hasPushState) { 
     pushStateSpy = spyOn(window.history, 'pushState').andCallFake(function (data, title, url) { 
      expect(url).toEqual('/'); 
      router.home(); 
     }); 
     router.navigate('', {trigger: true}); 
     expect(pushStateSpy).toHaveBeenCalled(); 
     expect(home).toHaveBeenCalled(); 

    } else if (Backbone.history._wantsHashChange) { 
     var updateHashSpy = spyOn(Backbone.history, '_updateHash').andCallFake(function (loc, frag) { 
      expect(frag).toEqual(''); 
      router.home(); 
     }); 
     router.navigate('', {trigger: true}); 
     expect(updateHashSpy).toHaveBeenCalled(); 
     expect(home).toHaveBeenCalled(); 
    } 
}); 

आप IE6 पर हैं, अच्छी किस्मत।

+0

हाय! यह अच्छा लग रहा है, लेकिन मैं यह नहीं देख सकता कि – Industrial

+0

से ऊपर बताए गए अनुसार, 'router.home()' के अंदर से वास्तविक तर्क को वास्तविक तर्क से कैसे रोकता है, कुंजी आपके स्थान को बदलने से इतिहास को रोकना है। यह आपको window.history पर जासूसी करके करने के लिए मिलता है, यह सत्यापित करता है कि यह काम करता है और फिर आपके स्थान को बदले बिना राउटर को कॉल करता है। फिर उपर्युक्त उदाहरण में आप यह जांच सकते हैं कि घर() ने आपके विचार बनाए हैं, डीओएम बदल दिया है या आप जो कुछ भी कर रहे हैं। – ggozad

+0

यदि आप router.home() में लॉगिन के अंदर भी कदम उठाना चाहते हैं तो आप निश्चित रूप से कर सकते हैं: homeSpy = spyOn (राउटर, 'होम')। और कॉलफैक (...); लेकिन pushStateSpy के बिना आप कभी नहीं मिलेगा। – ggozad

8

जब मैं रीढ़ की हड्डी राउटर का परीक्षण कर रहा हूं, तो मुझे क्या लगता है कि मेरे द्वारा प्रदान किए गए मार्ग सही तर्कों के साथ निर्दिष्ट कार्यों का आह्वान कर रहे हैं। यहां पर कई अन्य उत्तर वास्तव में इसका परीक्षण नहीं कर रहे हैं।

यदि आपको कुछ मार्गों की कार्यक्षमता का परीक्षण करने की आवश्यकता है, तो आप उन कार्यों का परीक्षण स्वयं कर सकते हैं।

मान लें कि आप एक साधारण रूटर है:

App.Router = Backbone.Router.extend({ 
    routes: { 
    '(/)':'index', 
    '/item/:id':'item' 
    }, 
    index: { 
    //render some template 
    }, 
    item: { 
    //render some other template, or redirect, or _whatever_ 
    } 
}); 

यहाँ कैसे मैं यह कर दिया गया है:

describe('Router', function() { 

    var trigger = {trigger: true}; 
    var router 

    beforeEach(function() { 
    // This is the trick, right here: 
    // The Backbone history code dodges our spies 
    // unless we set them up exactly like this: 
    Backbone.history.stop(); //stop the router 
    spyOn(Router.prototype, 'index'); //spy on our routes, and they won't get called 
    spyOn(Router.prototype, 'route2'); 

    router = new App.Router(); // Set up the spies _before_ creating the router 
    Backbone.history.start(); 
    }); 

    it('empty route routes to index', function(){ 
    Backbone.history.navigate('', trigger); 
    expect(router.index).toHaveBeenCalled(); 
    }); 

    it('/ routes to index', function(){ 
    router.navigate('/', trigger); 
    expect(router.index).toHaveBeenCalled(); 
    }); 

    it('/item routes to item with id', function(){ 
    router.navigate('/item/someId', trigger); 
    expect(router.item).toHaveBeenCalledWith('someId'); 
    }); 
}); 
+0

यह वही है जो मैं ढूंढ रहा था। इसके पीछे आपके तर्क को समझाते हुए इनलाइन टिप्पणियों के लिए भी धन्यवाद! – broox

0

मैं _updateHash जो आंशिक रूप से मेरे लिए काम किया पर जासूसी की ggozad के समाधान का उपयोग कर बाहर शुरू कर दिया। हालांकि, मैंने पाया कि मेरे परीक्षण उलझन में थे क्योंकि हैश ने कभी अपडेट नहीं किया था, इसलिए getHash या getFragment पर कॉल पर निर्भर कोड विफल रहे।

जो मैंने समाप्त किया वह निम्नलिखित सहायक कार्य है जो _updateHash और getHash दोनों पर जासूसी करता है। पूर्व में हैश को अपडेट करने का अनुरोध रिकॉर्ड करता है, और बाद वाला अंतिम हैश देता है जो _updateHash पर पारित किया गया था। बैकबोन इतिहास शुरू करने से पहले मैं अपने परीक्षण में इस सहायक समारोह को कॉल करता हूं।

/** 
    * Prevent Backbone tests from changing the browser's URL. 
    * 
    * This function modifies Backbone so that tests can navigate 
    * without modifying the browser's URL. It works be adding 
    * stub versions of Backbone's hash functions so that updating 
    * the hash doesn't change the URL but instead updates a 
    * local object. The router's callbacks are still invoked 
    * so that to the test it appears that navigation is behaving 
    * as expected. 
    * 
    * Note: it is important that tests don't update the browser's 
    * URL because subsequent tests could find themselves in an 
    * unexpected navigation state. 
    */ 
    preventBackboneChangingUrl = function() { 
     var history = { 
      currentFragment: '' 
     }; 

     // Stub out the Backbone router so that the browser doesn't actually navigate 
     spyOn(Backbone.history, '_updateHash').andCallFake(function (location, fragment, replace) { 
      history.currentFragment = fragment; 
     }); 

     // Stub out getHash so that Backbone thinks that the browser has navigated 
     spyOn(Backbone.history, 'getHash').andCallFake(function() { 
      return history.currentFragment; 
     }); 
    }; 
संबंधित मुद्दे