2017-07-11 1 views
1

I mis en œuvre une fonction de modèle pour MongoDB avec node-mongodb-native:Node.js - Appliquer sinon sur les tests unité de MongoDB

'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; 

Maintenant, je veux écrire des tests unitaires pour elle, compte 3 cas:

  • Une insertion réussie
  • échouent en raison de violer index unique
  • échouer en raison de la perte de connexion

Ayant ceux dans l'esprit, voici mes 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))); 
    }); 

}); 

J'appelle de véritables fonctions dans les tests, ce qui est apparemment difficile et beaucoup de temps en temps d'exécution pour éviter les effets secondaires à mon humble avis. Mais actuellement je n'ai pas trouvé d'autres idées en dehors de la modification d'une base de données de test. Est-il possible d'utiliser sinon? J'ai lu plusieurs blogs sur sinon, espion, talon, et faux, mais luttent pour les comprendre et les distinguer. Comment pourrais-je les appliquer à ces tests?

Répondre

1

Ce que vous avez écrit actuellement sont des tests d'intégration qui testent l'interaction entre votre serveur de noeud et la base de données mongo db. Bien que ces tests prennent plus de temps que les tests unitaires simulés, ils fournissent en réalité beaucoup plus de valeur. L'exécution de requêtes sur une instance stable de MongoDB garantit que vos requêtes s'exécutent comme prévu et que votre application répond correctement aux résultats, voir: How to unit test a method which connects to mongo, without actually connecting to mongo?.

Si vous souhaitez tester les fonctions javascript qui manipulent les données, par opposition à l'interaction entre le serveur et la base de données. Je vous suggère de refactoriser ce code à partir de la logique de requête mongodb et de le tester. Alternativement, lorsque vous utilisez une classe, vous devriez pouvoir écraser la propriété _db avec une bibliothèque mock db. Ce qui serait juste un objet avec des méthodes qui imitent celle de la bibliothèque mongo que vous utilisez actuellement. Ou vous pouvez utiliser sinon pour remplacer ces méthodes et les remplacer par des méthodes qui renvoient un résultat connu, voir http://sinonjs.org/releases/v1.17.7/stubs/.

Essayez quelque chose comme ceci:

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

Je suis encore très confus comment utiliser 'sinon' pour bouchonner ces méthodes. Pourriez-vous écrire un exemple pour moi selon ces codes ci-dessus? – necroface

+1

vient d'écrire une mise à jour que vous pourriez essayer –

+0

Merci beaucoup, il aide en effet – necroface