2012-03-01 11 views
76

मैं नोड.जेएस सीखने की प्रक्रिया में हूं और Express के साथ खेल रहा हूं। वास्तव में ढांचे की तरह; हालांकि, मुझे एक मार्ग के लिए एक इकाई/एकीकरण परीक्षण कैसे लिखना है, यह समझने में परेशानी हो रही है।एक्सप्रेस के साथ एक इकाई परीक्षण मार्ग कैसे करता है?

इकाई परीक्षण सरल मॉड्यूल में सक्षम होने के नाते आसान है और Mocha के साथ ऐसा कर रहा है; हालांकि, एक्सप्रेस के साथ मेरा यूनिट परीक्षण विफल रहता है क्योंकि प्रतिक्रिया ऑब्जेक्ट में मैं गुजर रहा हूं, मानों को बरकरार नहीं रखता है।

मार्ग-फंक्शन टेस्ट के तहत (मार्गों/index.js):

exports.index = function(req, res){ 
    res.render('index', { title: 'Express' }) 
}; 

यूनिट टेस्ट मॉड्यूल:

var should = require("should") 
    , routes = require("../routes"); 

var request = {}; 
var response = { 
    viewName: "" 
    , data : {} 
    , render: function(view, viewData) { 
     viewName = view; 
     data = viewData; 
    } 
}; 

describe("Routing", function(){ 
    describe("Default Route", function(){ 
     it("should provide the a title and the index view name", function(){ 
     routes.index(request, response); 
     response.viewName.should.equal("index"); 
     }); 

    }); 
}); 

जब मैं इस चलाने के लिए, यह "त्रुटि के लिए विफल रहता है: वैश्विक लीक का पता चला: व्यूनाम, डेटा "।

  1. मैं गलत कहां जा रहा हूं ताकि मैं यह काम कर सकूं?

  2. क्या इस स्तर पर मेरे कोड का परीक्षण करने के लिए मेरे लिए एक बेहतर तरीका है?

अद्यतन 1. सही कोड स्निपेट के बाद से मैं शुरू में भूल गया "यह()"।

उत्तर

18

आपकी प्रतिक्रिया वस्तु बदलें:

var response = { 
    viewName: "" 
    , data : {} 
    , render: function(view, viewData) { 
     this.viewName = view; 
     this.data = viewData; 
    } 
}; 

और यह काम करेंगे।

+1

धन्यवाद। पता था कि यह कुछ आसान था। – JamesEggers

18

एक्सप्रेस के साथ HTTP परीक्षण करने के लिए सबसे आसान तरीका है चोरी करने के लिए है TJ's http helper

मैं personally use his helper

it("should do something", function (done) { 
    request(app()) 
    .get('/session/new') 
    .expect('GET', done) 
}) 

आप वस्तु, उसके बाद सही mocks में पास विशेष रूप से अपने मार्गों परीक्षण करना चाहते हैं

describe("Default Route", function(){ 
    it("should provide the a title and the index view name", function(done){ 
     routes.index({}, { 
      render: function (viewName) { 
       viewName.should.equal("index") 
       done() 
      } 
     }) 
    }) 
}) 
+5

क्या आप 'सहायक' लिंक को ठीक कर सकते हैं? –

+0

@ निकोलसमुरे [टेस्ट-सर्वर] (https://github.com/Raynos/test-server) – Raynos

+14

ऐसा लगता है कि HTTP इकाई परीक्षण के लिए अधिक अद्यतित दृष्टिकोण [supertest] का उपयोग करना है (https: // github विजनमेडिया द्वारा .com/visionmedia/supertest)। ऐसा लगता है कि टीजे का http सहायक सुपरमार्केट के लिए विकसित हुआ है। –

26

जैसा कि अन्य ने टिप्पणियों में अनुशंसा की है, ऐसा लगता है कि एक्सप्रेस नियंत्रकों का परीक्षण करने के लिए कैननिकल तरीकाके माध्यम से है 0।

एक उदाहरण परीक्षण इस प्रकार दिखाई देंगे:

describe('GET /users', function(){ 
    it('respond with json', function(done){ 
    request(app) 
     .get('/users') 
     .set('Accept', 'application/json') 
     .expect(200) 
     .end(function(err, res){ 
     if (err) return done(err); 
     done() 
     }); 
    }) 
}); 

उल्टा: यदि आप एक ही बार में अपने पूरे ढेर परीक्षण कर सकते हैं।

डाउनसाइड: यह महसूस करता है और एकीकरण परीक्षण की तरह थोड़ा कार्य करता है।

+1

मुझे यह पसंद है, लेकिन क्या दृश्यनाम (मूल प्रश्न के रूप में) पर जोर देने का कोई तरीका है - या हमें प्रतिक्रिया की सामग्री पर जोर देना होगा? – Alex

+10

मैं आपके नकारात्मक पक्ष से सहमत हूं, यह यूनिट परीक्षण नहीं है। यह आपके आवेदन के यूआरएल का परीक्षण करने के लिए आपकी सभी इकाइयों के एकीकरण पर निर्भर करता है। –

+4

मुझे लगता है कि यह कहना कानूनी है कि "मार्ग" वास्तव में एक 'एकीकरण' है, और शायद परीक्षण मार्गों को एकीकरण परीक्षणों के लिए छोड़ा जाना चाहिए। मेरा मतलब है, उनके परिभाषित कॉलबैक से मेल खाने वाले मार्गों की कार्यक्षमता संभवतः पहले से ही express.js द्वारा परीक्षण की जाती है; किसी रूट के अंतिम परिणाम प्राप्त करने के लिए कोई आंतरिक तर्क, आदर्श रूप से इसके बाहर मॉड्यूलर किया जाना चाहिए, और उन मॉड्यूल को यूनिट परीक्षण किया जाना चाहिए। उनकी बातचीत, यानी, मार्ग, एकीकरण परीक्षण किया जाना चाहिए। क्या आप सहमत हैं? –

15

मैं इस निष्कर्ष पर पहुंचा हूं कि वास्तव में इकाई परीक्षण एक्सप्रेस अनुप्रयोगों का एकमात्र तरीका अनुरोध हैंडलर और आपके मूल तर्क के बीच बहुत से अलगाव को बनाए रखना है।

इस प्रकार, आपका आवेदन तर्क अलग मॉड्यूल में होना चाहिए जो require डी और यूनिट परीक्षण किया जा सकता है, और इस तरह एक्सप्रेस अनुरोध और प्रतिक्रिया कक्षाओं पर न्यूनतम निर्भरता हो सकती है।

फिर अनुरोध हैंडलर में आपको अपने मूल तर्क वर्गों के उचित तरीकों को कॉल करने की आवश्यकता है।

एक बार जब मैं अपने वर्तमान ऐप को पुनर्गठन पूरा कर लेता हूं तो मैं एक उदाहरण दूंगा!

मुझे लगता है कि this? की तरह कुछ लगता है (जिस्ट या टिप्पणी को फोर्क करने के लिए स्वतंत्र महसूस करें, मैं अभी भी इसका अन्वेषण कर रहा हूं)।

संपादित

यहाँ एक छोटे से उदाहरण इनलाइन है,। अधिक विस्तृत उदाहरण के लिए the gist देखें।

/// usercontroller.js 
var UserController = { 
    _database: null, 
    setDatabase: function(db) { this._database = db; }, 

    findUserByEmail: function(email, callback) { 
     this._database.collection('usercollection').findOne({ email: email }, callback); 
    } 
}; 

module.exports = UserController; 

/// routes.js 

/* GET user by email */ 
router.get('/:email', function(req, res) { 
    var UserController = require('./usercontroller'); 
    UserController.setDB(databaseHandleFromSomewhere); 
    UserController.findUserByEmail(req.params.email, function(err, result) { 
     if (err) throw err; 
     res.json(result); 
    }); 
}); 
3

अगर gjohnson से एक्सप्रेस 4 टिप्पणी इस उदाहरण के साथ इकाई परीक्षण:

var express = require('express'); 
var request = require('supertest'); 
var app = express(); 
var router = express.Router(); 
router.get('/user', function(req, res){ 
    res.send(200, { name: 'tobi' }); 
}); 
app.use(router); 
request(app) 
    .get('/user') 
    .expect('Content-Type', /json/) 
    .expect('Content-Length', '15') 
    .expect(200) 
    .end(function(err, res){ 
    if (err) throw err; 
    }); 
0

मैं इस रूप में अच्छी तरह सोच रहा था, लेकिन विशेष रूप से इकाई परीक्षण और नहीं एकीकरण परीक्षण के लिए। यह अभी मैं क्या कर रहा हूँ,

test('/api base path', function onTest(t) { 
    t.plan(1); 

    var path = routerObj.path; 

    t.equals(path, '/api'); 
}); 


test('Subrouters loaded', function onTest(t) { 
    t.plan(1); 

    var router = routerObj.router; 

    t.equals(router.stack.length, 5); 
}); 

कहाँ routerObj सिर्फ {router: expressRouter, path: '/api'} है। मैं फिर var loginRouterInfo = require('./login')(express.Router({mergeParams: true})); के साथ सबराउटर्स में लोड करता हूं और फिर एक्सप्रेस ऐप एक पैरामीटर के रूप में एक्सप्रेस राउटर में एक इनिट-फ़ंक्शन को कॉल करता है। InitRouter तो subrouter माउंट करने के लिए router.use(loginRouterInfo.path, loginRouterInfo.router); कहते हैं।

subrouter के साथ परीक्षण किया जा सकता है:

var test = require('tape'); 
var routerInit = require('../login'); 
var express = require('express'); 
var routerObj = routerInit(express.Router()); 

test('/login base path', function onTest(t) { 
    t.plan(1); 

    var path = routerObj.path; 

    t.equals(path, '/login'); 
}); 


test('GET /', function onTest(t) { 
    t.plan(2); 

    var route = routerObj.router.stack[0].route; 

    var routeGetMethod = route.methods.get; 
    t.equals(routeGetMethod, true); 

    var routePath = route.path; 
    t.equals(routePath, '/'); 
}); 
+3

यह वास्तव में दिलचस्प लगता है। क्या आपके पास गायब टुकड़ों के अधिक उदाहरण हैं यह दिखाने के लिए कि यह सब एक साथ कैसे फिट बैठता है? – cjbarth

1

इकाई परीक्षण के बजाय एकीकरण परीक्षण प्राप्त करने के लिए, मैं अनुरोध हैंडलर की प्रतिक्रिया ऑब्जेक्ट मज़ाक उड़ाया।

/* app.js */ 
import endpointHandler from './endpointHandler'; 
// ... 
app.post('/endpoint', endpointHandler); 
// ... 

/* endpointHandler.js */ 
const endpointHandler = (req, res) => { 
    try { 
    const { username, location } = req.body; 

    if (!(username && location)) { 
     throw ({ status: 400, message: 'Missing parameters' }); 
    } 

    res.status(200).json({ 
     location, 
     user, 
     message: 'Thanks for sharing your location with me.', 
    }); 
    } catch (error) { 
    console.error(error); 
    res.status(error.status).send(error.message); 
    } 
}; 

export default endpointHandler; 

/* response.mock.js */ 
import { EventEmitter } from 'events'; 

class Response extends EventEmitter { 
    private resStatus; 

    json(response, status) { 
    this.send(response, status); 
    } 

    send(response, status) { 
    this.emit('response', { 
     response, 
     status: this.resStatus || status, 
    }); 
    } 

    status(status) { 
    this.resStatus = status; 
    return this; 
    } 
} 

export default Response; 

/* endpointHandler.test.js */ 
import Response from './response.mock'; 
import endpointHandler from './endpointHander'; 

describe('endpoint handler test suite',() => { 
    it('should fail on empty body', (done) => { 
    const res = new Response(); 

    res.on('response', (response) => { 
     expect(response.status).toBe(400); 
     done(); 
    }); 

    endpointHandler({ body: {} }, res); 
    }); 
}); 

फिर, एकीकरण परीक्षण प्राप्त करने के लिए, आप अपने endpointHandler नकली और supertest साथ endpoint कॉल कर सकते हैं।

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