2016-04-29 3 views
3

Ich versuche zu automatisieren meine Datenbank wird gebaut, gesät und zerstört für jeden Test. Ich benutze PostgreSQL, Mocha und Sequelize.Aufbau, Seeding und Zerstörung von PostgreSQL mit Sequelize zum Testen

Ich habe eine Bibliothek gefunden: sequelize-fixtures das hat mich Teil Weg dorthin, aber letztlich ist es sehr inkonsistent und wird gelegentlich Constraint Fehler werfen: Unhandled rejection SequelizeUniqueConstraintError: Validation error, obwohl ich keine Validierung auf dem Modell haben.

Hier ist, wie ich die Tests tue

const sequelize = new Sequelize('test_db', 'db', null, { 
    logging: false, 
    host: 'localhost', 
    port: '5432', 
    dialect: 'postgres', 
    protocol: 'postgres' 
}) 

describe('/auth/whoami',() => { 
    beforeEach((done) => { 
    Fixtures.loadFile('test/fixtures/data.json', models) 
     .then(function(){ 
     done() 
     }) 
    }) 

    afterEach((done) => { 
    sequelize.sync({ 
     force: true 
    }).then(() => { 
     done() 
    }) 
    }) 

    it('should connect to the DB', (done) => { 
    sequelize.authenticate() 
     .then((err) => { 
     expect(err).toBe(undefined) 
     done() 
     }) 
    }) 

    it('should test getting a user', (done) => { 
    models.User.findAll({ 
     attributes: ['username'], 
    }).then((users) => { 
     users.forEach((user) => { 
     console.log(user.password) 
     }) 
     done() 
    }) 
    }) 
}) 

Mein Modell wie so definiert:

var Sequelize = require('sequelize'), 
    db = require('./../utils/db') 

var User = db.define('User', { 
    username: { 
    type: Sequelize.STRING(20), 
    allowNull: false, 
    notEmpty: true 
    }, 
    password: { 
    type: Sequelize.STRING(60), 
    allowNull: false, 
    notEmpty: true 
    } 
}) 

module.exports = User 

Die Fehlerprotokolle:

Fixtures: reading file test/fixtures/data.json... 
Executing (default): CREATE TABLE IF NOT EXISTS "Users" ("id" SERIAL , "username" VARCHAR(20) NOT NULL, "password" VARCHAR(60) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id")); 
Executing (default): SELECT "id", "username", "password", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."id" = 1 AND "User"."username" = 'Test User 1' AND "User"."password" = 'testpassword'; 
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Users' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname; 
Executing (default): INSERT INTO "Users" ("id","username","password","createdAt","updatedAt") VALUES (1,'Test User 1','testpassword','2016-04-29 23:15:08.828 +00:00','2016-04-29 23:15:08.828 +00:00') RETURNING *; 
Unhandled rejection SequelizeUniqueConstraintError: Validation error 

Diese einmal gearbeitet, dann nie wieder . Gibt es einen robusteren Weg für mich, vor jedem Test mit einer komplett sauberen DB zu beginnen, die ich mit Testdaten füllen kann?

This is the closest I have come to finding any kind of discussion/answer.


Außerdem, wenn jemand auch weiß, warum ich immer noch console.logs() auch bekommen, obwohl ich logging: false auf haben, die geschätzt werden würde.

+0

Wie ist Ihr Modell definiert? Logging false bedeutet, Sequelize wird das SQL nicht zur Konsole drucken. In Ihrem Fall sollten Sie Protokoll aktivieren, um alle Informationen zu Ihrem Problem zu erhalten. – denisazevedo

+0

@denisazevedo Ich habe meinen Beitrag mit meiner Modelldefinition und den Protokollen aktualisiert. Ich habe versucht, die Protokollierung zu deaktivieren, aber aus irgendeinem Grund erzeugt es immer noch die Protokolle, so dass ich sie immer noch sehe. –

Antwort

0

Der Fehler, den Sie eingefügt haben, scheint darauf hinzuweisen, dass dieselben Daten mehrmals eingefügt werden, was zu einem Konflikt in der Spalte id führt.

Ich würde erwarten, Aufruf sequelize.sync({force: true}) würde alle Datenbanktabellen für Sie bei jedem Lauf löschen, aber das scheint nicht der Fall zu sein. Sie könnten versuchen, Ihren Anruf an einen beforeEach-Hook weiterzuleiten, um sicherzustellen, dass dieser erste Test auch eine neue Datenbank enthält.

In einer Anwendung, an der ich arbeite, werden die Datenbank nicht für jeden Test neu synchronisiert, sondern nur einmal am Anfang und Tabellen zwischen den Tests abgeschnitten. Wir verwenden eine Bereinigungsfunktion, die wie folgt aussieht:

function cleanup() { 
    return User.destroy({ truncate: true, cascade: true }); 
} 

Eine create Methode macht die Arbeit zum Laden von Daten aus json Armaturen und sie in die Datenbank einfügen.

function create() { 
    var users = require('./fixtures/user.json'); 
    return User.bulkCreate(users); 
} 

Sie könnten in der Lage sein, Ihre Abhängigkeiten zu vereinfachen und die Stabilität zu verbessern, indem sequelize-fixtures Weglassen und Dinge selbst Handhabung.

Auch ein unabhängiger Vorschlag: Sequelize Methoden Versprechen zurück, die Mocha nativ verarbeiten kann, so dass keine Notwendigkeit, den done Rückruf in Ihren Tests und Setup/Teardown-Code zu verwenden:

it('should connect to the DB',() => { 
    return sequelize.authenticate() 
}) 

Der Test schlägt fehl, wenn die Versprechen wird abgelehnt.

Auch Mocha's docs empfehlen derzeit gegen die Verwendung von Pfeil Funktionen:

zu Mocha Passing Pfeil Funktionen abgeraten.Ihre lexikalische Bindung des Werts this macht es ihnen unmöglich, auf den Mocha-Kontext zuzugreifen, und Anweisungen wie this.timeout(1000); funktionieren nicht innerhalb einer Pfeilfunktion.