এক্সপ্রেসের সাথে কীভাবে এক ইউনিট পরীক্ষার রুট হয়?


101

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

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

পরীক্ষার অধীনে রুট-ফাংশন (রুটস / ইনডেক্স.জেএস):

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. সঠিক কোড স্নিপেট যেহেতু আমি প্রাথমিকভাবে "এটি ()" ভুলে গেছি।

উত্তর:


21

আপনার প্রতিক্রিয়া অবজেক্ট পরিবর্তন করুন:

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

এবং এটি কাজ করবে।


4
এটি রুট নয়, একটি অনুরোধ হ্যান্ডলারের পরীক্ষা করছে unit
জেসন সেব্রিং

44

অন্যরা যেমন মন্তব্যে সুপারিশ করেছে, দেখে মনে হচ্ছে এক্সপ্রেস নিয়ন্ত্রণকারীদের পরীক্ষা করার আধ্যাত্মিক উপায়টি অতিপুঞ্জের মাধ্যমে ।

একটি উদাহরণ পরীক্ষা হতে পারে:

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()
      });
  })
});

Psর্ধ্বমুখী: আপনি একবারে আপনার পুরো স্ট্যাকটি পরীক্ষা করতে পারেন।

ডাউনসাইড: এটি অনুভূতি হয় এবং কিছুটা সংহতকরণ পরীক্ষার মতো কাজ করে।


4
আমি এটি পছন্দ করি, তবে ভিউনাম (মূল প্রশ্নের মতো) জোর দেওয়ার কোনও উপায় আছে - বা আমাদের কী প্রতিক্রিয়ার বিষয়বস্তুতে দৃ ?়তা জানাতে হবে?
অ্যালেক্স

22
আমি আপনার খারাপ দিকের সাথে একমত, এটি ইউনিট পরীক্ষা নয়। এটি আপনার অ্যাপ্লিকেশনটির ইউআরএল পরীক্ষা করতে আপনার সমস্ত ইউনিটের একীকরণের উপর নির্ভর করে।
লুক এইচ

11
আমি মনে করি যে এটি "আইন" সত্যই একটি integrationএবং এটি সম্ভবত আইনী রুটগুলি ইন্টিগ্রেশন পরীক্ষার দিকে রেখে দেওয়া উচিত বলে আইনী মনে হয় । আমি বলতে চাইছি, তাদের সংজ্ঞায়িত কলব্যাকের সাথে মিলে যাওয়া রুটের কার্যকারিতা সম্ভবত এক্সপ্রেস.জেএস দ্বারা ইতিমধ্যে পরীক্ষা করা হয়েছে; কোনও রুটের চূড়ান্ত ফলাফল পাওয়ার জন্য কোনও অভ্যন্তরীণ যুক্তি, আদর্শভাবে এটির বাইরে মডিউলাইজ করা উচিত এবং সেইগুলি মডিউলগুলি ইউনিট পরীক্ষা করা উচিত। তাদের মিথস্ক্রিয়া, অর্থাৎ রুটটি ইন্টিগ্রেশন পরীক্ষা করা উচিত। তুমি কি রাজি?
আদিত্য এমপি

4
এটি শেষ থেকে শেষের পরীক্ষা। কোনো সন্দেহ নেই.
কেজিপিডিপোভার

25

আমি এই সিদ্ধান্তে পৌঁছেছি যে সত্যই ইউনিট পরীক্ষা এক্সপ্রেস অ্যাপ্লিকেশনগুলির একমাত্র উপায় হ'ল অনুরোধ পরিচালনাকারী এবং আপনার মূল যুক্তির মধ্যে অনেকগুলি বিচ্ছিন্নতা বজায় রাখা।

সুতরাং, আপনার অ্যাপ্লিকেশন যুক্তি হতে পারে পৃথক মডিউল মধ্যে হওয়া উচিত require ডি এবং ইউনিট পরীক্ষা করা এবং এক্সপ্রেস অনুরোধ এবং প্রতিক্রিয়া শ্রেণীর উপর ন্যূনতম নির্ভরতা থাকতে পারে।

তারপরে অনুরোধ হ্যান্ডলারগুলিতে আপনাকে আপনার মূল লজিক ক্লাসগুলির উপযুক্ত পদ্ধতিগুলি কল করতে হবে।

আমার বর্তমান অ্যাপটি পুনর্গঠন শেষ করার পরে আমি একটি উদাহরণ স্থাপন করব!

আমি এই জাতীয় কিছু অনুমান ? (সংক্ষিপ্ত বিবরণ বা মন্তব্য বিনা দ্বিধায় থাকুন, আমি এখনও এটি অন্বেষণ করছি)।

সম্পাদনা করুন

এখানে একটি ছোট উদাহরণ, ইনলাইন। আরও বিশদ উদাহরণের জন্য গিস্টটি দেখুন ।

/// 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);
    });
});

4
আমার মতে, এটি ব্যবহারের সেরা প্যাটার্ন। ভাষাগুলির অনেকগুলি ওয়েব ফ্রেমওয়ার্কগুলি ব্যবসার লজিককে প্রকৃত http প্রতিক্রিয়া গঠনের কার্যকারিতা থেকে পৃথক করতে নিয়ামক প্যাটার্ন ব্যবহার করে। এইভাবে, আপনি কেবল যুক্তিটি পরীক্ষা করতে পারেন এবং পুরো পোস্ট প্রতিক্রিয়া প্রক্রিয়া নয়, যা ফ্রেমওয়ার্কের বিকাশকারীদের নিজেরাই পরীক্ষা করা উচিত। এই প্যাটার্নে পরীক্ষা করা যেতে পারে এমন অন্যান্য জিনিসগুলি হ'ল সাধারণ মিডলওয়্যারস, কিছু বৈধতা ফাংশন এবং অন্যান্য ব্যবসায়িক পরিষেবা। ডিবি কানেক্টিভিটি টেস্টিং যদিও সম্পূর্ণ ভিন্ন ধরণের পরীক্ষা
OzzyTheGiant

4
প্রকৃতপক্ষে, এখানে প্রচুর উত্তরগুলি সত্যই একীকরণ / কার্যকরী পরীক্ষার সাথে করণীয়।
লুক এইচ

এটি সঠিক উত্তর। এক্সপ্রেস নয়, আপনার যুক্তি পরীক্ষার দিকে মনোযোগ দেওয়া উচিত।
এসমিরালহা

19

এক্সপ্রেসের সাথে এইচটিটিপি পরীক্ষা করার সবচেয়ে সহজ উপায় টিজির এইচটিপি সাহায্যকারী চুরি করা

আমি ব্যক্তিগতভাবে তার সহায়ক ব্যবহার করি

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

আপনি যদি নিজের রুটগুলি নির্দিষ্টভাবে পরীক্ষা করতে চান তবে সঠিক বিদ্রূপে পাস করুন

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()
            }
        })
    })
})

4
আপনি কি 'সহায়ক' লিঙ্কটি ঠিক করতে পারবেন?
নিকোলাস মারে

16
দেখে মনে হয় এইচটিটিপি ইউনিট পরীক্ষার জন্য আরও আপ-টু-ডেট পদ্ধতির ভিশনমিডিয়া দ্বারা সুপারস্টেট ব্যবহার করা । এটিও মনে হয় টিজির এইচটিপি সাহায্যকারী সর্বাধিক উন্নত হয়েছে।
আকসেলি পলান

4
গিথুবতে সেরা পাওয়া যাবে এখানে
ব্র্যান্ডন

@ রায়নস আপনি কীভাবে ব্যাখ্যা করতে পারেন যে আপনি কীভাবে আপনার উদাহরণটিতে একটি অনুরোধ এবং অ্যাপ পান?
jmcollin92

9
দুঃখের বিষয় এটি ইউনিট পরীক্ষার চেয়ে ইন্টিগ্রেশন টেস্টিং।
লুক এইচ

8

এক্সপ্রেস 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;
  });

1

আমি এটির পাশাপাশি ভাবছিলাম, তবে বিশেষত ইউনিট পরীক্ষার জন্য এবং ইন্টিগ্রেশন পরীক্ষার জন্য নয়। আমি এখনই এটি করছি

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);
});

যেখানে রাউটারঅবজে ঠিক আছে {router: expressRouter, path: '/api'}। আমি তারপরে সাবউটারগুলিতে লোড করি var loginRouterInfo = require('./login')(express.Router({mergeParams: true}));এবং তারপরে এক্সপ্রেস অ্যাপ্লিকেশনটি প্যারামিটার হিসাবে এক্সপ্রেস রাউটারে নিয়ে যাওয়া একটি ইন-ফাংশন কল করে। এরপরে আরআরউটার সাবউটারটি router.use(loginRouterInfo.path, loginRouterInfo.router);মাউন্ট করার জন্য কল করে।

সাব্রোটার দিয়ে পরীক্ষা করা যেতে পারে:

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, '/');
});

4
এটি সত্যিই আকর্ষণীয় দেখায়। কীভাবে এই সমস্ত একসাথে খাপ খায় তা দেখানোর জন্য কী আপনার হারিয়ে যাওয়া টুকরোগুলির আরও উদাহরণ রয়েছে?
সিজেবার্থ

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);
  });
});

তারপরে, ইন্টিগ্রেশন টেস্টিং অর্জনের জন্য, আপনি আপনার শেষ পয়েন্ট হ্যান্ডলারকে উপহাস করতে পারেন এবং শেষের পয়েন্টটিকে সুপারস্টেটের সাথে কল করতে পারেন ।


0

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

// ProductController.ts

import { Request, Response } from "express";

class ProductController {
  getAll(req: Request, res: Response): void {
    console.log("this has not been implemented yet");
  }
}
export default ProductController

রুটগুলি

// routes.ts
import ProductController  from "./ProductController"

const app = express();
const productController = new ProductController();
app.get("/product", productController.getAll);

পরীক্ষাগুলো

// routes.test.ts

import request from "supertest";
import { Request, Response } from "express";

const mockGetAll = jest
  .fn()
  .mockImplementation((req: Request, res: Response) => {
    res.send({ value: "Hello visitor from the future" });
  });

jest.doMock("./ProductController", () => {
  return jest.fn().mockImplementation(() => {
    return {
      getAll: mockGetAll,

    };
  });
});

import app from "./routes";

describe("Routes", () => {
  beforeEach(() => {
    mockGetAll.mockImplementation((req: Request, res: Response) => {
      res.send({ value: "You can also change the implementation" });
    });
  });

  it("GET /product integration test", async () => {
    const result = await request(app).get("/product");

    expect(mockGetAll).toHaveBeenCalledTimes(1);

  });



  it("GET an undefined route should return status 404", async () => {
    const response = await request(app).get("/random");
    expect(response.status).toBe(404);
  });
});


কাজ করার জন্য উপহাস করার জন্য আমার কিছু সমস্যা ছিল। তবে jest.doMock এবং উদাহরণটিতে আপনি যে নির্দিষ্ট আদেশটি দেখেছেন তা ব্যবহার করে এটি কার্যকর হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.