成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【譯】測(cè)試驅(qū)動(dòng)開發(fā):使用 Node.js 和 MongoDB 構(gòu)建 Todo API

邱勇 / 1174人閱讀

摘要:首先安裝單元測(cè)試環(huán)境使用模塊來模擬定義的模型。根據(jù)刪除這是單元測(cè)試的最后一小節(jié)。需要根據(jù)需求和單元測(cè)試用例來編寫應(yīng)用邏輯,使我們的程序更加穩(wěn)定。我們會(huì)運(yùn)行自動(dòng)測(cè)試用例,一直重構(gòu),直到所有單元測(cè)試都通過。

本文轉(zhuǎn)載自:眾成翻譯
譯者:文藺
鏈接:http://www.zcfy.cc/article/746
原文:https://semaphoreci.com/community/tutorials/a-tdd-approach-to-building-a-todo-api-using-node-js-and-mongodb

學(xué)習(xí)如何使用測(cè)試驅(qū)動(dòng)開發(fā)的方式,用 Node.js、MongoDB、Mocha 和 Sinon.js 開發(fā) Todo API。

簡(jiǎn)介

測(cè)試是軟件開發(fā)過程中的一個(gè)完整部分,它幫助我們提升軟件品質(zhì)。有很多種測(cè)試方法,如手動(dòng)測(cè)試,集成測(cè)試,功能測(cè)試,負(fù)載測(cè)試,單元測(cè)試等等。在本文中,我們將會(huì)遵循測(cè)試驅(qū)動(dòng)開發(fā)的規(guī)則編寫代碼。

單元測(cè)試是什么?

Martin Fowler 將單元測(cè)試定義如下:

首先一個(gè)概念,單元測(cè)試是低層次的,專注于軟件系統(tǒng)的一小部分;

其次,單元測(cè)試通常是由程序員使用常規(guī)工具自己編寫的 —— 唯一的區(qū)別是使用某種單元測(cè)試框架;

再次,單元測(cè)試預(yù)計(jì)比其他類型的測(cè)試顯著地更快。

在本教程中,我們將會(huì)使用 Node.js 和 MongoDB 構(gòu)建一個(gè) Todo API。我們首先會(huì)給生產(chǎn)代碼寫單元測(cè)試,然后才會(huì)真正寫生產(chǎn)代碼。

環(huán)境

Express.js

MongoDB

Mocha

Chai

Sinon.js

項(xiàng)目設(shè)置

在我們真正開發(fā) API 之前,我們必須設(shè)置文件夾和端點(diǎn)(end point)。

在軟件項(xiàng)目中,沒有最好的應(yīng)用架構(gòu)。本教程使用的文件結(jié)構(gòu),請(qǐng)看該 GitHub 倉庫。

現(xiàn)在來創(chuàng)建端點(diǎn)(endpoints):

安裝依賴

Node.js 有自己的包管理工具 NPM。要學(xué)習(xí)更多關(guān)于 NPM 的知識(shí),可以看我們的另一篇教程,《Node.js Package Manager tutorial》。

好,我們來安裝項(xiàng)目依賴。

npm install express mongoose method-override morgan body-parser cors —save-dev
定義 Schema

我們會(huì)使用 Mongoose 作為 Node.js 中的對(duì)象文檔模型(Object Document Model),它工作起來和典型的 ORM一樣,就像 Rails 中用 ActiveRecord一樣。Mongoose 幫我們更方便地訪問 MongoDB 命令。首先我們?yōu)?Todo API 定義 schema。

var mongoose = require("mongoose");
var Schema = mongoose.Schema;
// Defining schema for our Todo API
var TodoSchema = Schema({
  todo: {
    type: String
  },
  completed: {
    type: Boolean,
    default: false
  },
  created_by: {
    type: Date,
    default: Date.now
  }
});
//Exporting our model
var TodoModel = mongoose.model("Todo", TodoSchema);

module.exports = TodoModel;

Mongoose 中的一切都是從 schema 開始。每個(gè) schema 對(duì)應(yīng)一個(gè) MongoDB 集合,它定義了集合中文檔的形狀。

在上面的 todo schema 中,我們創(chuàng)建了三個(gè)字段來存儲(chǔ) todo 描述、狀態(tài)和創(chuàng)建日期。該 schema 幫助 Node.js 應(yīng)用理解如何將 MongoDB 中的數(shù)據(jù)映射成 JavaScript 對(duì)象。

搭建 Express Server

我們將使用 Express 來搭建服務(wù)器,它是一個(gè)小型 Node.js web 框架,提供了一個(gè)強(qiáng)大的功能集,用于開發(fā)Web應(yīng)用程序。

我們繼續(xù),搭建 Express server。

首先,我們要按下面這樣引入項(xiàng)目依賴:

var express = require("express");
var mongoose = require("mongoose");
var morgan = require("morgan");
var bodyParser = require("body-parser");
var methodOverride = require("method-override");
var app = express();
var config = require("./app/config/config");

接著,配置 Express 中間件:

app.use(morgan("dev")); // log every request to the console
app.use(bodyParser.urlencoded({"extended":"true"})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: "application/vnd.api+json" })); // parse application/vnd.api+json as json
app.use(methodOverride());
管理 Mongoose 連接

使用mongoose.connect將 MongoDB 和應(yīng)用連接,這會(huì)和數(shù)據(jù)庫建立連接。這就是連接 todoapi 數(shù)據(jù)庫的最小操作,數(shù)據(jù)庫跑在本地,默認(rèn)端口是 27017。如果本地連接失敗,試試將 localhost 換成 127.0.0.1。

有時(shí)候本地主機(jī)名改變時(shí)會(huì)出現(xiàn)一些問題。

//Connecting MongoDB using mongoose to our application
mongoose.connect(config.db);

//This callback will be triggered once the connection is successfully established to MongoDB
mongoose.connection.on("connected", function () {
  console.log("Mongoose default connection open to " + config.db);
});

//Express application will listen to port mentioned in our configuration
app.listen(config.port, function(err){
  if(err) throw err;
  console.log("App listening on port "+config.port);
});

使用下面的命令啟動(dòng)服務(wù)器:

//starting our node server
> node server.js
App listening on port 2000
為 API 編寫測(cè)試用例

在 TDD(測(cè)試驅(qū)動(dòng)開發(fā))中,將所有可能的輸入、輸出以及錯(cuò)誤納入考慮,然后開始編寫測(cè)試用例。來給我們的 Todo API 編寫測(cè)試用例吧。

搭建測(cè)試環(huán)境

之前提到過,我們會(huì)使用 Mocha 作為測(cè)試運(yùn)行器,Chai 作為斷言庫,用 Sinon.js 模擬 Todo model。首先安裝單元測(cè)試環(huán)境:

> npm install mocha chai sinon sinon-mongoose --save

使用 sinon-mongoose 模塊來模擬 Mongoose 定義的 MongoDB 模型。

現(xiàn)在,引入測(cè)試的依賴:

var sinon = require("sinon");
var chai = require("chai");
var expect = chai.expect;

var mongoose = require("mongoose");
require("sinon-mongoose");

//Importing our todo model for our unit testing.
var Todo = require("../../app/models/todo.model");
Todo API 的測(cè)試用例

編寫單元測(cè)試時(shí),需要同時(shí)考慮成功和出錯(cuò)的場(chǎng)景。

對(duì)我們的 Todo API 來說,我們要給新建、刪除、更新、查詢 API 同時(shí)編寫成功和出錯(cuò)的測(cè)試用例。我們使用 Mocha, Chai 和 Sinon.js 來編寫測(cè)試。

獲取所有 Todo

本小節(jié),我們來編寫從數(shù)據(jù)庫獲取所有 todo 的測(cè)試用例。需要同時(shí)為成功、出錯(cuò)場(chǎng)景編寫,以確保代碼在生產(chǎn)中的各種環(huán)境下都能正常工作。

我們不會(huì)使用真實(shí)數(shù)據(jù)庫來跑測(cè)試用例,而是用 sinon.mock 給 Todo schema 建立假數(shù)據(jù)模型,然后再測(cè)試期望的結(jié)果。

來使用 sinon.mock 給 Todo model 據(jù),然后使用 find 方法獲取數(shù)據(jù)庫中存儲(chǔ)的所有 todo。

    describe("Get all todos", function(){
         // Test will pass if we get all todos
        it("should return all todos", function(done){
            var TodoMock = sinon.mock(Todo);
            var expectedResult = {status: true, todo: []};
            TodoMock.expects("find").yields(null, expectedResult);
            Todo.find(function (err, result) {
                TodoMock.verify();
                TodoMock.restore();
                expect(result.status).to.be.true;
                done();
            });
        });

        // Test will pass if we fail to get a todo
        it("should return error", function(done){
            var TodoMock = sinon.mock(Todo);
            var expectedResult = {status: false, error: "Something went wrong"};
            TodoMock.expects("find").yields(expectedResult, null);
            Todo.find(function (err, result) {
                TodoMock.verify();
                TodoMock.restore();
                expect(err.status).to.not.be.true;
                done();
            });
        });
    });
保存 New Todo

保存一個(gè)新的 todo,需要用一個(gè)示例任務(wù)來模擬 Todo model。使用我們創(chuàng)建的Todo model來檢驗(yàn) mongoose 的save 方法保存 todo 到數(shù)據(jù)庫的結(jié)果。

    // Test will pass if the todo is saved
    describe("Post a new todo", function(){
        it("should create new post", function(done){
            var TodoMock = sinon.mock(new Todo({ todo: "Save new todo from mock"}));
            var todo = TodoMock.object;
            var expectedResult = { status: true };
            TodoMock.expects("save").yields(null, expectedResult);
            todo.save(function (err, result) {
                TodoMock.verify();
                TodoMock.restore();
                expect(result.status).to.be.true;
                done();
            });
        });
        // Test will pass if the todo is not saved
        it("should return error, if post not saved", function(done){
            var TodoMock = sinon.mock(new Todo({ todo: "Save new todo from mock"}));
            var todo = TodoMock.object;
            var expectedResult = { status: false };
            TodoMock.expects("save").yields(expectedResult, null);
            todo.save(function (err, result) {
                TodoMock.verify();
                TodoMock.restore();
                expect(err.status).to.not.be.true;
                done();
            });
        });
    });
根據(jù) ID 更新 Todo

本節(jié)我們來檢驗(yàn) API 的 update 功能。這和上面的例子很類似,除了我們要使用withArgs方法,模擬帶有參數(shù) ID 的 Todo model。

  // Test will pass if the todo is updated based on an ID
  describe("Update a new todo by id", function(){
    it("should updated a todo by id", function(done){
      var TodoMock = sinon.mock(new Todo({ completed: true}));
      var todo = TodoMock.object;
      var expectedResult = { status: true };
      TodoMock.expects("save").withArgs({_id: 12345}).yields(null, expectedResult);
      todo.save(function (err, result) {
        TodoMock.verify();
        TodoMock.restore();
        expect(result.status).to.be.true;
        done();
      });
    });
    // Test will pass if the todo is not updated based on an ID
    it("should return error if update action is failed", function(done){
      var TodoMock = sinon.mock(new Todo({ completed: true}));
      var todo = TodoMock.object;
      var expectedResult = { status: false };
      TodoMock.expects("save").withArgs({_id: 12345}).yields(expectedResult, null);
      todo.save(function (err, result) {
        TodoMock.verify();
        TodoMock.restore();
        expect(err.status).to.not.be.true;
        done();
      });
    });
  });
根據(jù) ID 刪除 Todo

這是 Todo API 單元測(cè)試的最后一小節(jié)。本節(jié)我們將基于給定的 ID ,使用 mongoose 的 remove 方法,測(cè)試 API 的 delete 功能。

    // Test will pass if the todo is deleted based on an ID
    describe("Delete a todo by id", function(){
        it("should delete a todo by id", function(done){
            var TodoMock = sinon.mock(Todo);
            var expectedResult = { status: true };
            TodoMock.expects("remove").withArgs({_id: 12345}).yields(null, expectedResult);
            Todo.remove({_id: 12345}, function (err, result) {
                TodoMock.verify();
                TodoMock.restore();
                expect(result.status).to.be.true;
                done();
            });
        });
        // Test will pass if the todo is not deleted based on an ID
        it("should return error if delete action is failed", function(done){
            var TodoMock = sinon.mock(Todo);
            var expectedResult = { status: false };
            TodoMock.expects("remove").withArgs({_id: 12345}).yields(expectedResult, null);
            Todo.remove({_id: 12345}, function (err, result) {
                TodoMock.verify();
                TodoMock.restore();
                expect(err.status).to.not.be.true;
                done();
            });
        });
    });

每次我們都要還原(restore) Todomock,確保下次它還能正常工作。

每次運(yùn)行測(cè)試用例的時(shí)候,所有的都會(huì)失敗,因?yàn)槲覀兊纳a(chǎn)代碼還沒寫好呢。我們會(huì)運(yùn)行自動(dòng)化測(cè)試,直至所有單元測(cè)試都通過。

> npm test

  Unit test for Todo API
    Get all todo
      1) should return all todo
      2) should return error
    Post a new todo
      3) should create new post
      4) should return error, if post not saved
    Update a new todo by id
      5) should updated a todo by id
      6) should return error if update action is failed
    Delete a todo by id
      7) should delete a todo by id
      8) should return error if delete action is failed

  0 passing (17ms)
  8 failing 

你在命令行終端上運(yùn)行npm test的時(shí)候,會(huì)得到上面的輸出信息,所有的測(cè)試用例都失敗了。需要根據(jù)需求和單元測(cè)試用例來編寫應(yīng)用邏輯,使我們的程序更加穩(wěn)定。

編寫應(yīng)用邏輯

下一步就是為 Todo API 編寫真正的應(yīng)用代碼。我們會(huì)運(yùn)行自動(dòng)測(cè)試用例,一直重構(gòu),直到所有單元測(cè)試都通過。

配置路由

對(duì)客戶端和服務(wù)端的 web 應(yīng)用來說,路由配置是最重要的一部分。在我們的應(yīng)用中,使用 Express Router 的實(shí)例來處理所有路由。來給我們的應(yīng)用創(chuàng)建路由。

var express = require("express");
var router = express.Router();

var Todo = require("../models/todo.model");
var TodoController = require("../controllers/todo.controller")(Todo);

// Get all Todo
router.get("/todo", TodoController.GetTodo);

// Create new Todo
router.post("/todo", TodoController.PostTodo);

// Delete a todo based on :id
router.delete("/todo/:id", TodoController.DeleteTodo);

// Update a todo based on :id
router.put("/todo/:id", TodoController.UpdateTodo);

module.exports = router;
Controller(控制器)

現(xiàn)在我們差不多在教程的最后階段了,開始來寫控制器代碼。在典型的 web 應(yīng)用里,controller 控制著保存、檢索數(shù)據(jù)的主要邏輯,還要做驗(yàn)證。來寫Todo API 真正的控制器,運(yùn)行自動(dòng)化單元測(cè)試直至測(cè)試用例全部通過。

    var Todo = require("../models/todo.model");

    var TodoCtrl = {
        // Get all todos from the Database
        GetTodo: function(req, res){
            Todo.find({}, function(err, todos){
              if(err) {
                res.json({status: false, error: "Something went wrong"});
                return;
              }
              res.json({status: true, todo: todos});
            });
        },
        //Post a todo into Database
        PostTodo: function(req, res){
            var todo = new Todo(req.body);
            todo.save(function(err, todo){
              if(err) {
                res.json({status: false, error: "Something went wrong"});
                return;
              }
              res.json({status: true, message: "Todo Saved!!"});
            });
        },
        //Updating a todo status based on an ID
        UpdateTodo: function(req, res){
            var completed = req.body.completed;
            Todo.findById(req.params.id, function(err, todo){
            todo.completed = completed;
            todo.save(function(err, todo){
              if(err) {
                res.json({status: false, error: "Status not updated"});
              }
              res.json({status: true, message: "Status updated successfully"});
            });
            });
        },
        // Deleting a todo baed on an ID
        DeleteTodo: function(req, res){
          Todo.remove({_id: req.params.id}, function(err, todos){
            if(err) {
              res.json({status: false, error: "Deleting todo is not successfull"});
              return;
            }
            res.json({status: true, message: "Todo deleted successfully!!"});
          });
        }
    }

module.exports = TodoCtrl;
運(yùn)行測(cè)試用例

現(xiàn)在我們完成了應(yīng)用的測(cè)試用例和控制器邏輯兩部分。來跑一下測(cè)試,看看最終結(jié)果:

> npm test
  Unit test for Todo API
    Get all todo
      ? should return all todo
      ? should return error
    Post a new todo
      ? should create new post
      ? should return error, if post not saved
    Update a new todo by id
      ? should updated a todo by id
      ? should return error if update action is failed
    Delete a todo by id
      ? should delete a todo by id
      ? should return error if delete action is failed

  8 passing (34ms) 

最終結(jié)果顯示,我們所有的測(cè)試用例都通過了。接下來的步驟應(yīng)該是 API 重構(gòu),這包含著重復(fù)本教程提到的相同過程。

結(jié)論

通過本教程,我們學(xué)習(xí)了如果使用測(cè)試驅(qū)動(dòng)開發(fā)的辦法,用 Node.js and MongoDB 設(shè)計(jì) API。盡管 TDD (測(cè)試驅(qū)動(dòng)開發(fā))給開發(fā)過程帶來了額外復(fù)雜度,它能幫我們建立更穩(wěn)定的、錯(cuò)誤更少的應(yīng)用。就算你不想實(shí)踐 TDD, 至少也應(yīng)該編寫覆蓋應(yīng)用所有功能點(diǎn)的測(cè)試。

如果你有任何問題或想法,請(qǐng)不吝留言。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/79884.html

相關(guān)文章

  • 測(cè)試驅(qū)動(dòng)開發(fā)使用 Node.js MongoDB 構(gòu)建 Todo API

    摘要:首先安裝單元測(cè)試環(huán)境使用模塊來模擬定義的模型。根據(jù)刪除這是單元測(cè)試的最后一小節(jié)。需要根據(jù)需求和單元測(cè)試用例來編寫應(yīng)用邏輯,使我們的程序更加穩(wěn)定。我們會(huì)運(yùn)行自動(dòng)測(cè)試用例,一直重構(gòu),直到所有單元測(cè)試都通過。 本文轉(zhuǎn)載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/746原文:https://semaphoreci.com/community/tutoria...

    tomener 評(píng)論0 收藏0
  • 急速JavaScript全棧教程

    摘要:使用訪問后端服務(wù)使用的美化組件的方法整合全棧服務(wù)其中的指的是。所幸是在這個(gè)教程內(nèi),你不需要學(xué)習(xí)太多就可以把案例跑起來。另外一個(gè)組件負(fù)責(zé)顯示全部項(xiàng)目,并接受刪除事件,刪除指定的項(xiàng)目。它們分別是組件和組件這兩個(gè)組件的代碼實(shí)現(xiàn),分別在文件和內(nèi)。 自從一年前發(fā)布了Vuejs小書的電子書,也有些日子沒有碰過它們了,現(xiàn)在因?yàn)轫?xiàng)目的緣故,需要使用JavaScript全棧開發(fā)。所以,我得把這個(gè)全棧環(huán)境...

    xingqiba 評(píng)論0 收藏0
  • 急速JavaScript全棧教程

    摘要:使用訪問后端服務(wù)使用的美化組件的方法整合全棧服務(wù)其中的指的是。所幸是在這個(gè)教程內(nèi),你不需要學(xué)習(xí)太多就可以把案例跑起來。另外一個(gè)組件負(fù)責(zé)顯示全部項(xiàng)目,并接受刪除事件,刪除指定的項(xiàng)目。它們分別是組件和組件這兩個(gè)組件的代碼實(shí)現(xiàn),分別在文件和內(nèi)。 自從一年前發(fā)布了Vuejs小書的電子書,也有些日子沒有碰過它們了,現(xiàn)在因?yàn)轫?xiàng)目的緣故,需要使用JavaScript全棧開發(fā)。所以,我得把這個(gè)全棧環(huán)境...

    騫諱護(hù) 評(píng)論0 收藏0
  • GitHub 值得收藏的前端項(xiàng)目[每月更新...]

    摘要:也是一款優(yōu)秀的響應(yīng)式框架站點(diǎn)所使用的一套框架為微信服務(wù)量身設(shè)計(jì)的一套框架一組很小的,響應(yīng)式的組件,你可以在網(wǎng)頁的項(xiàng)目上到處使用一個(gè)可定制的文件,使瀏覽器呈現(xiàn)的所有元素,更一致和符合現(xiàn)代標(biāo)準(zhǔn)。 GitHub 值得收藏的前端項(xiàng)目 整理與收集的一些比較優(yōu)秀github項(xiàng)目,方便自己閱讀,順便分享出來,大家一起學(xué)習(xí),本篇文章會(huì)持續(xù)更新,版權(quán)歸原作者所有。歡迎github star與fork 預(yù)...

    maxmin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<