Testing with spy, stub, mock

Muthy Afifah
Auto Personalia
Published in
3 min readMay 17, 2017

membuat unit testing dengan Ajax, networking, database dan beberapa dependensi yang lain bisa menjadi cukup sulit. sebagai contoh dengan database, anda harus membuat testing database untuk test yang kita buat.

dengan sinon.js hal diatas dapat diatasi. untuk menggunakan sinon harus menginstall dahulu sinon dengan cara npm install sinon.

Example Function

function once(fn) {
var returnValue, called = false;
return function () {
if (!called) {
called = true;
returnValue = fn.apply(this, arguments);
}
return returnValue;
};
}

fungsi tersebut mempunyai paramter fungsi dan mengembalikan fungsi baru. result function bisa dipanggil berulang kali tetapi function once hanya dipanggil sekali.

Spies

seperti namaya, spies digunakan untuk mendapatkan informasi tentang function call. sebagai contoh, spy bisa memberi tahu berapa banyak fungsi dipanggil, apa argumen yang dimiliki, nilai yang dikembalikan, error yang ditangkap, dll. spy merupakan pilihan yang baik untuk memeriksa sesuatu terjadi atau tidak. kita juga bisa memeriksa apakah argumer di-passed dengan menggunakan sinon.assert.calledWith

it('calls the original function only once', function () {
var callback = sinon.spy();
var proxy = once(callback);
proxy();
proxy();
assert(callback.calledOnce);
// ...or:
// assert.equals(callback.callCount, 1);
});
it('calls original function with right this and args', function () {
var callback = sinon.spy();
var proxy = once(callback);
var obj = {};
proxy.call(obj, 1, 2, 3); assert(callback.calledOn(obj));
assert(callback.calledWith(1, 2, 3));
});

Stubs

stubs sama seperti spies, hanya saja stub mengganti target fungsi. stub bisa mengubah behavior dari fungsi seperti mengembalikan nilai tertentu atau mengembalikan error.

contoh fungsi:

function setupNewUser(info, callback) {
var user = {
name: info.name,
nameLowercase: info.name.toLowerCase()
};
try {
Database.save(user, callback);
}
catch(err) {
callback(err);
}
}

menggunakan stub

it('should pass object with correct values to save', function() {
var save = sinon.stub(Database, 'save');
var info = { name: 'test' };
var expectedUser = {
name: info.name,
nameLowercase: info.name.toLowerCase()
};
setupNewUser(info, function() { }); save.restore();
sinon.assert.calledWith(save, expectedUser);
});

dengan menggunakan stub, kita tidak lagi perlu database yang sesungguhnya untuk test ini. pendekatan yang sama bisa dilakukan untuk code yang susah untuk ditest.

stubs juga bisa melakukan testing terhadap error. berikut contohnya:

it('should pass the error into the callback if save fails', function() {
var expectedError = new Error('oops');
var save = sinon.stub(Database, 'save');
save.throws(expectedError);
var callback = sinon.spy();
setupNewUser({ name: 'foo' }, callback); save.restore();
sinon.assert.calledWith(callback, expectedError);
});

stubs bisa untuk mempermudah testing asynchronus coe. jika kita stub fungsinya maka akan memaksa untuk langsung memanggil callback sehingga testnya menjadi synchronus dan tidak perlu handling asynchronus test. berikut contohnya:

it('should pass the database result into the callback', function() {
var expectedResult = { success: true };
var save = sinon.stub(Database, 'save');
save.yields(null, expectedResult);
var callback = sinon.spy();
setupNewUser({ name: 'foo' }, callback); save.restore();
sinon.assert.calledWith(callback, null, expectedResult);
});

Mocks

Mocks bisa melakukan apa yang spies dan stubs lakukan tetapi mocks bisa membuat test yang dibuat menjadi overly specific yang bisa memungkinkan test breaks unintentionally ketika mengubah kode. dalam mocks bisa mendefinisikan multiple assertion yang harus dicek secara pasti agar tidak terjadi kesalahan. berikut contohnya:

it('should pass object with correct values to save only once', function() {
var info = { name: 'test' };
var expectedUser = {
name: info.name,
nameLowercase: info.name.toLowerCase()
};
var database = sinon.mock(Database);
database.expects('save').once().withArgs(expectedUser);
setupNewUser(info, function() { }); database.verify();
database.restore();
});

dengan mock, kita mendefinisikan ekspetasi di atas yang biasanya kita di belakang dalam bentuk assert function call. dengan mock, kita mendefinisikan secara langsung di mocked function dan hanya memanggil verify sekali di belakang

source:

https://semaphoreci.com/community/tutorials/best-practices-for-spies-stubs-and-mocks-in-sinon-js

--

--