Как вы издеваетесь над MySQL (без ORM) в Node.js?
Я использую Node.js
с клиентом felixge node-mysql
. Я не использую ORM.
Я тестирую с обетами и хочу быть в состоянии издеваться над моей базой данных, возможно, используя Sinon. Поскольку у меня действительно нет DAL per se (кроме node-mysql
), я не совсем уверен, как это сделать. Мои модели в основном простые CRUD с большим количеством геттеров.
Любые идеи о том, как это сделать?
Ответы
Ответ 1
С помощью синона вы можете наложить макет или заглушку вокруг всего модуля. Например, предположим, что модуль mysql
имеет функцию query
:
var mock;
mock = sinon.mock(require('mysql'))
mock.expects('query').with(queryString, queryParams).yields(null, rows);
queryString
, queryParams
- ожидаемый результат. rows
- ожидаемый результат.
Когда ваш тестируемый класс теперь требует mysql и вызывает метод query
, он будет перехвачен и проверен синоном.
В разделе ожидания тестирования вы должны:
mock.verify()
и в вашем teardown вы должны восстановить mysql до нормальной функциональности:
mock.restore()
Ответ 2
Это может быть хорошей идеей абстрагировать вашу базу данных в свой класс, который использует mysql. Затем вы можете передать экземпляр этого класса своим конструкторам моделей, а не загружать их с помощью require().
С помощью этой настройки вы можете передать экземпляр mock db в свои модели внутри ваших файлов unit test.
Вот небольшой пример:
// 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
Я не совсем знаком с node.js, но в традиционном смысле программирования, чтобы добиться такого же тестирования, вам нужно абстрагироваться от метода доступа к данным. Не могли бы вы создать класс DAL, например:
var DataContainer = function () {
}
DataContainer.prototype.getAllBooks = function() {
// call mysql api select methods and return results...
}
Теперь, в контексте теста, исправьте класс getAllBooks во время инициализации, например:
DataContainer.prototype.getAllBooks = function() {
// Here is where you'd return your mock data in whatever format is expected.
return [];
}
Когда вызывается тестовый код, getAllBooks будет заменен версией, которая возвращает макет данных вместо фактического вызова mysql. Опять же, это общий обзор, поскольку я не совсем знаком с node.js
Ответ 4
Вы можете издеваться над внешними зависимостями, используя horaa
И я также считаю, что felixge node sandboxed-module также может сделать что-то подобное.
Таким образом, используя тот же контекст, что и в kgalpin, он выглядел бы примерно так:
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');
Ответ 5
Я закончил с ответа @kgilpin и закончил с чем-то вроде этого, чтобы проверить Mysql в 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');
});
});
});
});
Мне не нужны какие-либо фактические подключения к базе данных, поэтому я вручную издевался над всеми ответами mysql.
Добавив еще одну функцию в .returns
, вы можете высмеять любой метод createConnection
.