MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Phương pháp lưu mô hình Mongoose chế nhạo / sơ khai

Khái niệm cơ bản

Trong thử nghiệm đơn vị, người ta không nên nhấn vào DB. Tôi có thể nghĩ đến một ngoại lệ:nhấn DB trong bộ nhớ, nhưng ngay cả điều đó cũng đã nằm trong lĩnh vực kiểm tra tích hợp vì bạn chỉ cần trạng thái được lưu trong bộ nhớ cho các quy trình phức tạp (và do đó không thực sự là đơn vị chức năng). Vì vậy, không có DB thực tế.

Những gì bạn muốn kiểm tra trong các bài kiểm tra đơn vị là logic nghiệp vụ của bạn dẫn đến các lệnh gọi API chính xác tại giao diện giữa ứng dụng của bạn và DB. Bạn có thể và có lẽ nên giả định rằng các nhà phát triển trình điều khiển / API DB đã thực hiện tốt công việc kiểm tra rằng mọi thứ bên dưới API hoạt động như mong đợi. Tuy nhiên, bạn cũng muốn đề cập trong các thử nghiệm của mình cách logic nghiệp vụ của bạn phản ứng với các kết quả API hợp lệ khác nhau, chẳng hạn như lưu thành công, thất bại do tính nhất quán của dữ liệu, thất bại do sự cố kết nối, v.v.

Điều này có nghĩa là những gì bạn cần và muốn mô phỏng là mọi thứ nằm bên dưới giao diện trình điều khiển DB. Tuy nhiên, bạn cần phải mô hình hóa hành vi đó để logic nghiệp vụ của bạn có thể được kiểm tra cho tất cả các kết quả của các lệnh gọi DB.

Nói thì dễ hơn làm vì điều này có nghĩa là bạn cần có quyền truy cập vào API thông qua công nghệ bạn sử dụng và bạn cần biết API.

Thực tế của cầy mangut

Bám sát những điều cơ bản, chúng tôi muốn chế nhạo các cuộc gọi được thực hiện bởi 'trình điều khiển' cơ bản mà mongoose sử dụng. Giả sử đó là node-mongodb-native chúng ta cần chế nhạo những lời kêu gọi đó. Hiểu được sự tương tác đầy đủ giữa mongoose và trình điều khiển gốc không phải là điều dễ dàng, nhưng nó thường phụ thuộc vào các phương thức trong mongoose.Collection vì cái sau mở rộng mongoldb.Collection không các phương thức thực hiện lại như insert . Nếu chúng tôi có thể kiểm soát hành vi của insert trong trường hợp cụ thể này, sau đó chúng tôi biết rằng chúng tôi đã chế nhạo quyền truy cập DB ở cấp API. Bạn có thể theo dõi nó trong nguồn của cả hai dự án, Collection.insert thực sự là phương thức trình điều khiển gốc.

Đối với ví dụ cụ thể của bạn, tôi đã tạo kho lưu trữ Git công khai với một gói hoàn chỉnh, nhưng tôi sẽ đăng tất cả các yếu tố ở đây trong câu trả lời.

Giải pháp

Cá nhân tôi thấy cách làm việc "được đề xuất" với mongoose khá không sử dụng được:các mô hình thường được tạo trong các mô-đun nơi các lược đồ tương ứng được xác định, nhưng chúng đã cần kết nối. Đối với mục đích có nhiều kết nối để nói chuyện với cơ sở dữ liệu mongodb hoàn toàn khác nhau trong cùng một dự án và cho mục đích thử nghiệm, điều này làm cho cuộc sống thực sự khó khăn. Trên thực tế, ngay khi những mối lo ngại được tách ra hoàn toàn, ít nhất là đối với tôi, gần như không sử dụng được.

Vì vậy, điều đầu tiên tôi tạo là tệp mô tả gói, một mô-đun có lược đồ và "trình tạo mô hình" chung:

{
  "name": "xxx",
  "version": "0.1.0",
  "private": true,
  "main": "./src",
  "scripts": {
    "test" : "mocha --recursive"
  },
  "dependencies": {
    "mongoose": "*"
  },
  "devDependencies": {
    "mocha": "*",
    "chai": "*"
  }
}
var mongoose = require("mongoose");

var PostSchema = new mongoose.Schema({
    title: { type: String },
    postDate: { type: Date, default: Date.now }
}, {
    timestamps: true
});

module.exports = PostSchema;
var model = function(conn, schema, name) {
    var res = conn.models[name];
    return res || conn.model.bind(conn)(name, schema);
};

module.exports = {
    PostSchema: require("./post"),
    model: model
};

Một trình tạo mô hình như vậy có nhược điểm của nó:có những phần tử có thể cần được gắn vào mô hình và sẽ rất hợp lý nếu đặt chúng trong cùng một mô-đun nơi lược đồ được tạo. Vì vậy, tìm một cách chung chung để thêm những thứ đó là một chút khó khăn. Ví dụ:một mô-đun có thể xuất các hành động hậu để được tự động chạy khi một mô hình được tạo cho một kết nối nhất định, v.v. (tấn công).

Bây giờ hãy giả lập API. Tôi sẽ giữ nó đơn giản và sẽ chỉ mô phỏng những gì tôi cần cho các bài kiểm tra được đề cập. Điều cần thiết là tôi muốn mô phỏng API nói chung, không phải các phương pháp riêng lẻ của các trường hợp riêng lẻ. Cái sau có thể hữu ích trong một số trường hợp hoặc khi không có gì khác hữu ích, nhưng tôi sẽ cần có quyền truy cập vào các đối tượng được tạo bên trong logic nghiệp vụ của mình (trừ khi được đưa vào hoặc cung cấp thông qua một số mẫu nhà máy) và điều này có nghĩa là phải sửa đổi nguồn chính. Đồng thời, việc chế nhạo API ở một nơi có một nhược điểm:đó là một giải pháp chung chung, có thể sẽ triển khai thực thi thành công. Đối với các trường hợp lỗi thử nghiệm, có thể bắt buộc phải chế nhạo trong các trường hợp trong chính các thử nghiệm, nhưng trong logic kinh doanh của bạn, bạn có thể không có quyền truy cập trực tiếp vào trường hợp của ví dụ:post tạo sâu bên trong.

Vì vậy, chúng ta hãy xem xét trường hợp chung của việc chế nhạo lệnh gọi API thành công:

var mongoose = require("mongoose");

// this method is propagated from node-mongodb-native
mongoose.Collection.prototype.insert = function(docs, options, callback) {
    // this is what the API would do if the save succeeds!
    callback(null, docs);
};

module.exports = mongoose;

Nói chung, miễn là các mô hình được tạo sau sửa đổi mongoose, có thể nghĩ rằng các mô phỏng ở trên được thực hiện trên cơ sở thử nghiệm để mô phỏng bất kỳ hành vi nào. Tuy nhiên, hãy đảm bảo hoàn nguyên về hành vi ban đầu trước mỗi lần kiểm tra!

Cuối cùng, đây là cách các bài kiểm tra của chúng tôi cho tất cả các hoạt động tiết kiệm dữ liệu có thể có. Hãy chú ý, những điều này không dành riêng cho Post của chúng tôi mô hình và có thể được thực hiện cho tất cả các mô hình khác với chính xác cùng một mô hình tại chỗ.

// now we have mongoose with the mocked API
// but it is essential that our models are created AFTER 
// the API was mocked, not in the main source!
var mongoose = require("./mock"),
    assert = require("assert");

var underTest = require("../src");

describe("Post", function() {
    var Post;

    beforeEach(function(done) {
        var conn = mongoose.createConnection();
        Post = underTest.model(conn, underTest.PostSchema, "Post");
        done();
    });

    it("given valid data post.save returns saved document", function(done) {
        var post = new Post({
            title: 'My test post',
            postDate: Date.now()
        });
        post.save(function(err, doc) {
            assert.deepEqual(doc, post);
            done(err);
        });
    });

    it("given valid data Post.create returns saved documents", function(done) {
        var post = new Post({
            title: 'My test post',
            postDate: 876543
        });
        var posts = [ post ];
        Post.create(posts, function(err, docs) {
            try {
                assert.equal(1, docs.length);
                var doc = docs[0];
                assert.equal(post.title, doc.title);
                assert.equal(post.date, doc.date);
                assert.ok(doc._id);
                assert.ok(doc.createdAt);
                assert.ok(doc.updatedAt);
            } catch (ex) {
                err = ex;
            }
            done(err);
        });
    });

    it("Post.create filters out invalid data", function(done) {
        var post = new Post({
            foo: 'Some foo string',
            postDate: 876543
        });
        var posts = [ post ];
        Post.create(posts, function(err, docs) {
            try {
                assert.equal(1, docs.length);
                var doc = docs[0];
                assert.equal(undefined, doc.title);
                assert.equal(undefined, doc.foo);
                assert.equal(post.date, doc.date);
                assert.ok(doc._id);
                assert.ok(doc.createdAt);
                assert.ok(doc.updatedAt);
            } catch (ex) {
                err = ex;
            }
            done(err);
        });
    });

});

Điều cần lưu ý là chúng tôi vẫn đang thử nghiệm chức năng ở mức rất thấp, nhưng chúng tôi có thể sử dụng cùng phương pháp này để kiểm tra bất kỳ logic nghiệp vụ nào sử dụng Post.create hoặc post.save trong nội bộ.

Phần cuối cùng, hãy chạy các bài kiểm tra:

> [email protected] test /Users/osklyar/source/web/xxx
> mocha --recursive

Post
  ✓ given valid data post.save returns saved document
  ✓ given valid data Post.create returns saved documents
  ✓ Post.create filters out invalid data

3 passing (52ms)

Tôi phải nói rằng, không có gì vui khi làm theo cách đó. Nhưng theo cách này, nó thực sự là thử nghiệm đơn vị thuần túy về logic nghiệp vụ mà không có bất kỳ DB trong bộ nhớ hoặc DB thực nào và khá chung chung.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Thứ tự sắp xếp ngẫu nhiên

  2. Cách chỉ lưu phần ngày tháng với mongoose, không phải ở định dạng ISODate

  3. Truy vấn mảng trong danh sách nhúng

  4. Xóa phần tử khỏi mảng trong mongodb

  5. Sự cố thiết lập Bản sao SSL MongoDB - Chứng chỉ không được hỗ trợ