2017-07-11 1 views
1

ich eine Modellfunktion für mongodb mit node-mongodb-native implementiert:node.js - Bewerben sinon auf mongodb Einheit testet

'use strict'; 

const mongo = require('mongodb'); 

class BlacklistModel { 

    constructor(db, tenant_id, logger) { 
     this._db = db; 
     this._table = 'blacklist_' + tenant_id; 
     this._logger = logger; 
    } 

    create(data) { 
     return new Promise((resolve, reject) => { 
      const options = { 
       unique: true, 
       background: true, 
       w: 1 
      }; 
      this._db.collection(this._table).ensureIndex({ phone: 1 }, options, (err) => { 
       if (err) { 
        this._logger.error(err); 
        reject(err); 
       } else { 
        const datetime = Date.parse(new Date()); 
        data._id = new mongo.ObjectID().toString(); 
        data.createdAt = datetime; 
        data.updatedAt = datetime; 
        this._db.collection(this._table).insertOne(data, (err) => { 
         if (err) { 
          this._logger.error(err); 
          reject(err); 
         } else { 
          resolve(data); 
         } 
        }); 
       } 
      }); 
     }); 
    } 

} 

module.exports = BlacklistModel; 

Jetzt möchte ich Unit-Tests für sie schreiben, 3 Fälle Berücksichtigung

  • Eine erfolgreiche Insertion
  • Ausfallen wegen Verstoßes gegen eindeutigen Index
  • Ausfallen aufgrund verlorener Verbindung

jene in den Köpfen Lager, hier sind meine Tests:

'use strict'; 

const chai = require('chai'); 
const chaiAsPromised = require('chai-as-promised'); 
chai.use(chaiAsPromised); 
const expect = chai.expect; 

const BlacklistModel = require('../../model/blacklist'); 

const mongo_url = require('../../config/mongodb'); 
const MongoClient = require('mongodb').MongoClient; 

const logger = require('../../config/logger'); 

const data = { 
    name: 'admin' 
}; 

describe('Model: Blacklist',() => { 

    let Blacklist; 
    let connected = false; 
    let test_db; 

    const connect =() => new Promise((resolve, reject) => { 
     MongoClient.connect(mongo_url, (err, db) => { 
      if (err) { 
       reject(err); 
      } else { 
       Blacklist = new BlacklistModel(db, 'test', logger); 
       connected = true; 
       test_db = db; 
       resolve(); 
      } 
     }); 
    }); 

    before(() => connect()); 

    describe('create',() => { 
     let id; 
     beforeEach(() => connected ? 
      null : connect()); 
     it('Should return an inserted document',() => { 
      return Blacklist.create(data).then(
       (result) => { 
        expect(result._id).to.be.a('string'); 
        expect(result.name).to.equal(data.name); 
        expect(result.createdAt).to.be.a('number'); 
        expect(result.updatedAt).to.be.a('number'); 
        id = result._id; 
       }); 
     }); 
     it('Should fail to insert a blacklist with the same name',() => { 
      const promise = Blacklist.create(data).then(
       (result) => { 
        id = result._id; 
        return Blacklist.create(data); 
       }); 
      return expect(promise).to.be.rejected; 
     }); 
     it('Should fail due to lost connection',() => { 
      return test_db.close(true).then(() => { 
       connected = false; 
       return expect(Blacklist.create(data)).to.be.rejected; 
      }); 
     }); 
     afterEach(() => connected ? 
      Blacklist.delete(id) : connect().then(() => Blacklist.delete(id))); 
    }); 

}); 

Ich nenne reelle Funktionen in Tests, die scheinbar umständlich und zeitraubend ist in Runtime Nebenwirkungen in meiner bescheidenen Meinung nach zu vermeiden. Aber zur Zeit habe ich keine anderen Ideen außer der Änderung einer Testdatenbank. Gibt es eine Möglichkeit, sinon zu verwenden? Ich habe mehrere Blogs über sinon, Spion, Stub und Spott gelesen, aber kämpfen, um sie zu verstehen und zu unterscheiden. Wie kann ich sie auf diese Tests anwenden?

Antwort

1

Was Sie gerade geschrieben haben, sind Integrationstests, die die Interaktion zwischen Ihrem Node-Server und der mongo db-Datenbank testen. Obwohl diese Tests zeitaufwändiger sind als verspottete Komponententests, bieten sie tatsächlich viel mehr Wert. Das Ausführen von Abfragen für eine stabile MongoDB-Instanz stellt sicher, dass Ihre Abfragen wie geplant ausgeführt werden und dass Ihre Anwendung ordnungsgemäß auf die Ergebnisse reagiert. Siehe: How to unit test a method which connects to mongo, without actually connecting to mongo?.

Wenn Sie die JavaScript-Funktionen testen möchten, die die Daten im Gegensatz zu der Interaktion zwischen dem Server und db manipulieren. Ich würde vorschlagen, dass Sie diesen Code aus der mongodb-Abfragelogik umdefinieren und testen. Alternativ, wie Sie eine Klasse verwenden, sollten Sie in der Lage sein, die _db-Eigenschaft mit einer Mock-Db-Bibliothek zu überschreiben. Das wäre nur ein Objekt mit Methoden, die denen der Mongo-Bibliothek ähneln, die Sie gerade verwenden. Oder Sie können sinon verwenden, um diese Methoden auszugeben und sie durch Methoden zu ersetzen, die ein bekanntes Ergebnis zurückgeben, siehe http://sinonjs.org/releases/v1.17.7/stubs/.

versuchen, etwas wie folgt aus:

var ensureIndex = { ensureIndex: sinon.stub() } 
sinon.stub(db, 'collection').returns(ensureIndex) 

var blackList; 

describe('Model: Blacklist',() => { 

    beforeEach(() => { 
    var blackList = new BlacklistModel(db, id, logger); 
    }) 
    it('test' => { 
    blackList.create(data).then(() => { 
     // some test here 
     db.collection.calledWithMatch('some match') 
    }) 

    }) 
}) 
+0

Ich bin immer noch sehr verwirrt, wie 'sinon' zu verwenden, um diese Methoden zu Stummel. Könnten Sie mir ein Beispiel für diese obigen Codes schreiben? – necroface

+1

Ich habe gerade ein Update geschrieben, dass Sie versuchen könnten –

+0

Vielen Dank, es hilft tatsächlich – necroface