2011-12-05 10 views
34

Używam klienta Node.js z klientem felixge: node-mysql. Nie używam ORM.Jak wyśmiewać MySQL (bez ORM) w Node.js?

Testuję z Ślubami i chcę mieć możliwość wyśmiewania się z mojej bazy danych, prawdopodobnie używając Sinona. Ponieważ naprawdę nie mam DAL per se (poza node-mysql), nie jestem naprawdę pewny, jak to zrobić. Moje modele to głównie prosty CRUD z dużą ilością pobierających.

Jakieś pomysły, jak to osiągnąć?

+0

Czy możesz podać mi więcej informacji? Na przykład wklej kod i pokaż prawdopodobnie pseudokod tego, co chcesz osiągnąć? Chciałbym pomóc. – alessioalex

+0

@alessioalex Szczerze mówiąc, nie wiem nawet, od czego zacząć. Naprawdę Idealnie chciałbym zobaczyć czyjąś klasę modelu i związane z nimi makiety/testy. –

Odpowiedz

22

Z Sinon, można umieścić makiety lub niedopałek wokół całego modułu. Na przykład, załóżmy, że moduł mysql posiada funkcję query:

var mock; 

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

queryString, queryParams to wejście można się spodziewać. rows to oczekiwana wydajność.

Gdy badana klasa wymaga teraz mysql i wywoła metodę query, zostanie przechwycona i zweryfikowana przez sinon.

W sekcji oczekiwanie testu trzeba mieć:

mock.verify() 

iw swoim przerywaniem należy przywrócić mysql z powrotem do normalnej funkcjonalności:

mock.restore() 
+1

.with() wydaje się być przestarzałe na rzecz .withArgs(). Testuję z sinonem 1.7.2 – AndreiM

+1

Chciałbym przegłosować, jeśli dasz pełny przykład. –

4

Nie jestem do końca obeznany z node.js, ale w tradycyjnym sensie programowania, aby uzyskać takie testy, trzeba odciąć się od metody dostępu do danych. nie można utworzyć klasę DAL takich jak:

var DataContainer = function() { 
} 

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

Teraz w ramach testu, załatać swoją klasę getAllBooks podczas inicjalizacji jak:

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

Gdy kod test jest nazywany, getAllBooks będzie zastąpiony przez wersję, która zwraca fałszywe dane zamiast wywoływać mysql. Ponownie, jest to ogólny przegląd, ponieważ nie jestem do końca obeznany z node.js

7

Dobrym pomysłem może być odesłanie bazy danych do własnej klasy, która używa mysql. Następnie możesz przekazać instancję tej klasy do konstruktorów twojego modelu, zamiast ładować ją za pomocą require().

Za pomocą tej konfiguracji można przekazać modelową instancję db do modeli w plikach testowych urządzenia.

Oto mały przykład:

// 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

Można kpić z zależnościami zewnętrznych za pomocą horaa

Wierzę też, że węzeł felixge'a sandboxed-module może również zrobić coś podobnego.

Więc używając tego samego kontekstu kgilpin jest w horaa to wyglądać mniej więcej tak:

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 wydaje się być defacto w tych dniach – dule

1

skończyło się zaczynając od użytkownika @ kgilpin odpowiedź i zakończył się z czymś takim do przetestowania Mysql w 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'); 
     }); 
    }); 
}); 
}); 

Nie chciałem żadnych rzeczywistych połączeń z bazami danych, więc ręcznie wyśmiewałem wszystkie odpowiedzi mysql.
Po dodaniu kolejnej funkcji do .returns można wysmakować dowolną metodę z poziomu createConnection.

Powiązane problemy