8

मैं MochaSinon के साथ अपने node.js मॉड्यूल का परीक्षण करने के लिए उपयोग कर रहा हूं। मैंने सफलतापूर्वक अन्य निर्भरताओं (अन्य मॉड्यूल जो मैंने लिखे हैं) का मज़ाक उड़ाया है, लेकिन मैंने गैर-शुद्ध कार्यों (जैसे Math.random() और Date.now()) को दबाकर समस्याओं में भाग लिया है। मैंने निम्नलिखित की कोशिश की है (सरलीकृत है कि यह प्रश्न इतना स्थानीय नहीं है), लेकिन Math.random() को स्पष्ट दायरे की समस्या के कारण स्कब नहीं किया गया था। Math के उदाहरण परीक्षण फ़ाइल और mymodule.js के बीच स्वतंत्र हैं।स्टबिंग दिनांक .now() और Math.random()

test.js

var sinon = require('sinon'), 
    mymodule = require('./mymodule.js'), 
    other = require('./other.js'); 

describe('MyModule', function() { 
    describe('funcThatDependsOnRandom', function() { 
     it('should call other.otherFunc with a random num when no num provided', function() { 
      sinon.mock(other).expects('otherFunc').withArgs(0.5).once(); 
      sinon.stub(Math, 'random').returns(0.5); 

      funcThatDependsOnRandom(); // called with no args, so should call 
             // other.otherFunc with random num 

      other.verify(); // ensure expectation has been met 
     }); 
    }); 
}); 

तो यह काल्पनिक उदाहरण में, functThatDependsOnRandom() दिखाई देगा:

mymodule.js

var other = require('./other.js'); 

function funcThatDependsOnRandom(num) { 
    if(typeof num === 'undefined') num = Math.random(); 

    return other.otherFunc(num); 
} 

यह संभव में Math.random() ठूंठ है साइनऑन के साथ यह परिदृश्य?

उत्तर

7

हाँ, यह एक पुराने सवाल यह है, लेकिन यह वैध है। यहां एक उत्तर दिया गया है जो काम करता है, हालांकि मुझे इसे बेहतर बनाने के सुझावों को सुनना अच्छा लगेगा।

जिस तरह से मैंने ब्राउज़र में इसका सामना किया है वह प्रॉक्सी ऑब्जेक्ट बनाना है। उदाहरण के लिए, आप ब्राउज़र में विंडो ऑब्जेक्ट को स्टब नहीं कर सकते हैं ताकि आप विंडो प्रॉक्सी नामक प्रॉक्सी ऑब्जेक्ट बना सकें। जब आप स्थान प्राप्त करना चाहते हैं तो आप windowProxy में एक विधि बनाते हैं जिसे स्थान स्थानांतरित या सेट करता है। फिर, परीक्षण करते समय, आप windowProxy.location mock।

आप यह वही चीज़ Node.js के साथ कर सकते हैं, लेकिन यह बस इतना ही काम नहीं करता है। सरल संस्करण यह है कि एक मॉड्यूल किसी अन्य मॉड्यूल के निजी नामस्थान के साथ गड़बड़ नहीं कर सकता है।

समाधान mockery मॉड्यूल का उपयोग करना है। मॉकरी शुरू करने के बाद, यदि आप पैरामीटर के साथ require() पर कॉल करते हैं जो मैक के लिए मॉकरी के बारे में बताता है, तो यह आपको आवश्यक कथन को ओवरराइड करने और अपनी खुद की संपत्तियों को वापस करने देगा।

अद्यतन: मैंने एक पूर्ण कार्यात्मक कोड उदाहरण बनाया है। यह Github at newz2000/dice-tdd और available via npm पर है।/अंत अद्यतन

डॉक्स बहुत अच्छे हैं, तो मैं उन्हें पढ़ने का सुझाव है, लेकिन यहां एक उदाहरण है: अपने कोड में फिर

module.exports.random = function() { 
    return Math.random(); 
} 

:

इस तरह की सामग्री के साथ एक फ़ाइल randomHelper.js बनाएं इसके लिए एक यादृच्छिक संख्या की आवश्यकता है, आप:

var randomHelper = require('./randomHelper'); 

console.log('A random number: ' + randomHelper.random()); 

सब कुछ सामान्य की तरह काम करना चाहिए। आपकी प्रॉक्सी ऑब्जेक्ट उसी तरह व्यवहार करती है जैसे Math.random।

यह ध्यान रखना महत्वपूर्ण है कि आवश्यक कथन एक पैरामीटर, './randomHelper' स्वीकार कर रहा है। हमें यह ध्यान रखना होगा।

अब आप अपने परीक्षण में

, (मैं उदाहरण के लिए मोचा और चाय का उपयोग कर रहा):

var sinon = require('sinon'); 
var mockery = require('mockery') 
var yourModule; // note that we didn't require() your module, we just declare it here 

describe('Testing my module', function() { 

    var randomStub; // just declaring this for now 

    before(function() { 
    mockery.enable({ 
     warnOnReplace: false, 
     warnOnUnregistered: false 
    }); 

    randomStub = sinon.stub().returns(0.99999); 

    mockery.registerMock('./randomHelper', randomStub) 
    // note that I used the same parameter that I sent in to requirein the module 
    // it is important that these match precisely 

    yourmodule = require('../yourmodule'); 
    // note that we're requiring your module here, after mockery is setup 
    } 

    after(function() { 
    mockery.disable(); 
    } 

    it('Should use a random number', function() { 
    callCount = randomStub.callCount; 

    yourmodule.whatever(); // this is the code that will use Math.random() 

    expect(randomStub.callCount).to.equal(callCount + 1); 
    } 
} 

और वह यह है। इस मामले में, हमारा स्टब हमेशा 0.0.9 99 99 लौटाएगा; आप निश्चित रूप से इसे बदल सकते हैं।

+0

उत्कृष्ट जवाब। आप मजाकिया के बजाय प्रॉक्सीक्वायर का भी उपयोग कर सकते हैं। – Wtower

0

क्या आप सुनिश्चित हैं कि Math का मज़ाक उड़ा नहीं है। ऐसा लगता है कि इस लाइन नहीं खास मतलब:

sinon.mock(other).expects('otherFunc').withArgs(0.5).once(); 

आप एक मॉड्यूल में others नकली लेकिन एक और एक में इसका इस्तेमाल करते हैं। मुझे नहीं लगता कि आपको mymodule.js में मजाकिया संस्करण मिलेगा। दूसरी तरफ Math.random को काम करना चाहिए, क्योंकि यह सभी मॉड्यूल के लिए वैश्विक है।

नोडजेएस परीक्षणों में निर्भरताओं पर नकल करने के लिए इस SO पर भी नज़र डालें।

+0

अगर मैं गलत हूं तो मुझे सही करें, लेकिन मैंने सोचा कि मॉड्यूल को उनकी फ्रिस्ट आवश्यकता के बाद कैश किया गया था। इसलिए, परीक्षण सूट में '(/ ./ other.js') की आवश्यकता है और परीक्षण किए जा रहे कोड में एक ही उदाहरण होना चाहिए। इस सोच के साथ, मैंने माना कि (जैसे 'Math.random') एक दूसरे में मजाक कर दूसरे में ऑब्जेक्ट को संशोधित करेगा। लेकिन शायद यह काम नहीं करता है क्योंकि यह गुणों को बदलने के बजाय अन्य को एक नई वस्तु निर्दिष्ट करता है। किसी भी तरह से आप इस के आसपास होने के sinon के साथ जानते हैं? –

1

प्रयास करें:

sinon.stub(Math, "random", function(){ 
    return 0.5; 
    }); 
+2

यह तब काम नहीं करता है जब Math.random() का उपयोग करने वाला फ़ंक्शन किसी अन्य मॉड्यूल में होता है। जब आप आरईपीएल का उपयोग कर रहे हों तो यह काम करता है या फ़ंक्शन एक ही .js फ़ाइल में है। – newz2000

संबंधित मुद्दे