2011-12-05 29 views
34

Tôi đang sử dụng Node.js với máy khách node-mysql của felixge. Tôi không sử dụng ORM.Làm thế nào để bạn giả lập MySQL (không có ORM) trong Node.js?

Tôi đang thử nghiệm với Vows và muốn có thể giả lập cơ sở dữ liệu của tôi, có thể sử dụng Sinon. Vì tôi không thực sự có một DAL mỗi (ngoài node-mysql), tôi không thực sự chắc chắn làm thế nào để đi về điều này. Các mô hình của tôi chủ yếu là CRUD đơn giản với rất nhiều getters.

Bất kỳ ý tưởng nào về cách thực hiện điều này?

+0

Bạn có thể cho tôi biết thêm chi tiết không? Ví dụ dán một số mã và hiển thị có lẽ là mã giả của những gì bạn muốn đạt được? Tôi muốn giúp đỡ. – alessioalex

+0

@alessioalex Tôi thành thật thậm chí không biết bắt đầu từ đâu. Thực sự lý tưởng tôi muốn xem lớp mô hình của người khác và các thử nghiệm/kiểm tra liên quan của họ. –

Trả lời

22

Với Sinon, bạn có thể đặt một giả hoặc còn sơ khai xung quanh toàn bộ mô-đun. Ví dụ, giả sử các module mysql có chức năng query:

var mock; 

mock = sinon.mock(require('mysql')) 
mock.expects('query').with(queryString, queryParams).yields(null, rows); 

queryString, queryParams là đầu vào bạn mong đợi. rows là đầu ra bạn mong đợi.

Khi lớp học của bạn đang được kiểm tra yêu cầu mysql và gọi phương thức query, nó sẽ bị chặn và xác minh bởi sinon.

Trong phần kỳ vọng thử nghiệm của bạn, bạn nên có:

mock.verify() 

và teardown của bạn, bạn nên khôi phục mysql trở lại chức năng bình thường:

mock.restore() 
+1

.với() dường như đã bị phản đối vì lợi ích của .withArgs(). Tôi đang thử nghiệm với sinon 1.7.2 – AndreiM

+1

Sẽ được upvoted nếu bạn đưa ra một ví dụ đầy đủ. –

4

Tôi không hoàn toàn quen thuộc với node.js, nhưng theo nghĩa lập trình truyền thống, để đạt được thử nghiệm như vậy, bạn cần trừu tượng ra khỏi phương pháp truy cập dữ liệu. bạn không thể tạo ra một lớp DAL như:

var DataContainer = function() { 
} 

DataContainer.prototype.getAllBooks = function() { 
    // call mysql api select methods and return results... 
} 

Bây giờ trong bối cảnh của một kiểm tra, vá lớp getAllBooks của bạn trong quá trình khởi như:

DataContainer.prototype.getAllBooks = function() { 
    // Here is where you'd return your mock data in whatever format is expected. 
    return []; 
} 

Khi mã kiểm tra được gọi, getAllBooks sẽ thay thế bằng một phiên bản trả về dữ liệu giả thay vì thực sự gọi mysql. Một lần nữa, đây là một tổng quan sơ lược vì tôi không hoàn toàn quen thuộc với node.js

7

Có thể là một ý tưởng tốt để trừu tượng hóa cơ sở dữ liệu của bạn thành lớp riêng của nó, sử dụng mysql. Sau đó, bạn có thể chuyển thể hiện của lớp đó tới các hàm tạo của mô hình của bạn thay vì chúng tải nó bằng cách sử dụng require().

Với thiết lập này, bạn có thể chuyển một phiên bản db giả cho các mô hình của bạn bên trong các tệp thử nghiệm đơn vị của bạn.

Dưới đây là một ví dụ nhỏ:

// db.js 
var Db = function() { 
    this.driver = require('mysql'); 
}; 
Db.prototype.query = function(sql, callback) { 
    this.driver... callback (err, results); 
} 
module.exports = Db; 

// someModel.js 
var SomeModel = function (params) { 
    this.db = params.db 
} 
SomeModel.prototype.getSomeTable (params) { 
    var sql = .... 
    this.db.query (sql, function (err, res) {...} 
} 
module.exports = SomeModel; 

// in app.js 
var db = new (require('./db.js'))(); 
var someModel = new SomeModel ({db:db}); 
var otherModel = new OtherModel ({db:db}) 

// in app.test.js 
var db = { 
    query: function (sql, callback) { ... callback ({...}) } 
} 
var someModel = new SomeModel ({db:db}); 
3

Bạn có thể thử ra phụ thuộc bên ngoài sử dụng horaa

Và tôi cũng tin rằng nút của felixge sandboxed-module cũng có thể làm điều tương tự.

Vì vậy, sử dụng bối cảnh tương tự kgilpin, trong horaa nó sẽ giống như thế:

var mock = horaa('mysql'); 
mock.hijack('query', function(queryString, queryParam) { 
    // do your fake db query (e.g., return fake expected data) 
}); 

//SUT calls and asserts 

mock.restore('query'); 
+0

sinon.js dường như là defacto những ngày này – dule

1

tôi đã kết thúc bắt đầu với câu trả lời @ kgilpin và kết thúc với một cái gì đó như thế này để kiểm tra Mysql trong một AWS Lambda:

const sinon = require('sinon'); 
const LambdaTester = require('lambda-tester'); 
const myLambdaHandler = require('../../lambdas/myLambda').handler; 
const mockMysql = sinon.mock(require('mysql')); 
const chai = require('chai'); 
const expect = chai.expect; 

describe('Database Write Requests', function() { 

beforeEach(() => { 
    mockMysql.expects('createConnection').returns({ 
    connect:() => { 
     console.log('Succesfully connected'); 
    }, 
    query: (query, vars, callback) => { 
     callback(null, succesfulDbInsert); 
    }, 
    end:() => { 
     console.log('Connection ended'); 
    } 
    }); 

}); 
after(() => { 
    mockMysql.restore(); 
}); 

describe('A call to write to the Database with correct schema', function() { 

    it('results in a write success', function() { 

    return LambdaTester(myLambdaHandler) 
     .event(anObject) 
     .expectResult((result) => { 
     expect(result).to.equal(succesfulDbInsert); 
     }); 
    }); 
}); 


describe('database errors', function() { 

    before(() => { 
    mockMysql.expects('createConnection').returns({ 
     connect:() => { 
     console.log('Succesfully connected'); 
     }, 
     query: (query, vars, callback) => { 
     callback('Database error!', null); 
     }, 
     end:() => { 
     console.log('Connection ended'); 
     } 
    }); 
    }); 

    after(() => { 
    mockMysql.restore(); 
    }); 

    it('results in a callback error response', function() { 


    return LambdaTester(myLambdaHandler) 
     .event(anObject) 
     .expectError((err) => { 
     expect(err.message).to.equal('Something went wrong'); 
     }); 
    }); 
}); 
}); 

Tôi không muốn bất kỳ kết nối cơ sở dữ liệu thực tế nào do đó tôi đã tự tay chế nhạo tất cả các phản hồi mysql.
Bằng cách thêm một chức năng khác vào .returns, bạn có thể giả lập bất kỳ phương thức nào là tắt của createConnection.

Các vấn đề liên quan