miércoles, 27 de agosto de 2014
martes, 5 de agosto de 2014
Testing javascript with jasmine/sinon
Spy
Un spy es
un objeto usado para registrar toda interacción con otros objetos, es una
función usada para registrar si se ha llamado y cuantas veces, con qué
argumentos, los valores devueltos, el valor de this, y cualquier excepción si
la hay para cada una de las llamadas a esa función.
Puede ser una función anónima, o
envolver a otra función existente controlando así lo anteriormente descrito. En
este último caso la función a la que envuelve sigue funcionando igual.
Los
datos guardados por el spy se guardan en un array args[][] de manera que
args[0] serán los argumentos recibidos en la primera llamada, args[1] en la
segunda y así consecutivamente.
Los valores devueltos se guardan
también en un array returnValues[], donde returnValues[0] sería el valor
devuelto en la primera llamada Si no devuelve valor alguno será undefined.
El valor de this se devuelve igual que
los valores devueltos pero con el array thisValues[].
Igual con las excepciones que irán en
el array exceptions[].
Los spies son útiles para controlar
llamadas a una función, que se llame con los argumentos adecuados, que devuelva
el valor correcto, etc…
Ejemplo de definición de un spy que
registrará todas las operaciones de Extjs.ajax sin interferir en su normal
funcionamiento:
sinon.spy
(jQuery,’ajax’);
jQuery.getJSON(‘/some/data’);
El spy no interferirá en el normal
funcionamiento de jQuery.ajax, pero registrará los datos asociados.
Los métodos más ususales para spy
suelen ser:
- calledOnce: si se ha llamado una sola vez.
- called: al menos una.
- calledTwice: dos veces.
- calledThrice: tres veces
- callCount: el nº de veces llamado
- calledWith(arg1, arg2,…): llamado con los argumentos indicados(puede incluir otros distintos).
- calledWithExactly(arg1, arg2,..): llamado con los argumentos indicados y ninguno más.
- Threw(): devolvió excepción.
Algunos ejemplos de spies:
Así se define un spy para que actúe
cobre el objeto controller.behaviourStore cuando se llame al método load:
storeLoadSpy = U4.testframework.spy(controller.behaviourStore,
'load');
Una vez definido llamaremos a
cualquier otro método que queramos saber si hace una llamada a load, y
controlaremos por ejemplo que se ha llamado y con los argumentos correctos
expect(storeLoadSpy.called).toBeTruthy();
expect(storeLoadSpy.args[0][0].listNodes).toBe(nodesList.toString());
Stub
Es un sustituto de la función a
la que envuelve, o un sustituto de una función que no existe. Permite definir
un comportamiento dado al llamar a esa función stub, es decir fijar unos parámetros
y que devuelva un valor fijo determinado. Stub implementa la interface spy, por
lo que también puede ser usado un stub a modo de spy.
Las dos principales razones para usar
stubs es enmascarar comportamientos, por ejemplo evitar la necesidad de tener
que hacer peticiones a un servidor, o evitar que una pantalla de confirmación
aparezca, etc.. y por otro lado proveer a los test de datos que normalmente son
suministrados por otras funciones sin tener que usarlas. Con esto aislamos el
test para evitar que otros aspectos externos al test puedan influir.
Los stubs se crean de las siguientes
formas:
· sinon.stub() crea stub function anónima.
· sinon.stub(object,”method”) crea un
stub para el método object.method
· sinon.stub(object,”method”,func) crea
un stub para el método object.method sustituyéndolo por la función func
·
Los métodos más usuales para stub son:
- returns(value) hace que el stub devuelva siempre ese valor.
- throws(exception) lanza una excepción, si exception es un string puede ser el tipo de excepción
- withArgs (arg1, arg2,…)
Algunos ejemplos de stubs
Crea stub de función anónima, y lo
define de manera que si se llama con el parámetro 42 devuelve 1, si se llama
con el 1 devuelve un error, y si no se usa argumento alguno entonces no
devuelve nada.
var
callback = sinon.stub();
callback.withArgs(42).returns(1);
callback.withArgs(1).throws("TypeError");
callback(); // No return value, no
exception
callback(42); // Returns 1
callback(1); // Throws TypeError
En el siguiente ejemplo de crea un
stub para el método getSelection del objeto behaviourView.grid.getSelectionModel(), que devolverá siempre un array con un record, es decir cada vez que se haga
una selección del grid se devuelve el mismo objeto
U4.testframework.stub(behaviourView.grid.getSelectionModel(),
'getSelection').returns([record]);
expect(behaviourView.fireEvent.calledWithExactly('inheritbehaviourmodified',record, behaviourSelected.originalValue)).toBeFalsy();
En este otro ejemplo usaremos un stub
para evitar que se haga la llamada al servidor, y como si fuera un spy
controlaremos que se ha hecho un POST sobre la url correcta, y con los datos
correctos:
saveChanges:
function (config) {
var me = this,
client,
jsonData =
me.fillJSONData(config.treeStore, config.behaviourStore, config.evidenceStore),
competenceGroupsPath =
'hrms/competence/competencegroups/';
U4.Ajax.setAccessId(me.accessId);
client = U4.util.Path.encodeSegment(me.client);
return U4.Ajax.promise({
url:
U4.util.Path.getApiPath(competenceGroupsPath + client),
method: 'POST',
jsonData: Ext.JSON.encode(jsonData)
});
},
promiseStub =
U4.testframework.stub(U4.Ajax, 'promise');
saveProxy.saveChanges(config);
expect(promiseStub.calledOnce).toBeTruthy();
expect(promiseStub.args[0][0].method).toBe('POST');
expect(promiseStub.args[0][0].url).toBe('hrms/competence/competencegroups/XX');
expect(promiseStub.args[0][0].jsonData).toBe(jsonDataExpected);
Ejemplo de crear un FakeServer que
simule un servidor que devuelva los datos a una petición de un store.load
(response debe ser un array con los elementos a devolver), igualmente se usa un
spy asociado a Ext.Ajax sobre el método ‘request’ para controlar si se hizo una llamada
fakeServer
= U4.testframework.createFakeServer();
fakeServer.respondWith('GET',
new RegExp('.*hrms/competence/competencegroups/.*'),
[200, { 'Content-Type': 'application/json'
},
response]);
spyAjaxRequest
= U4.testframework.spy(Ext.Ajax, 'request');
store.load({
listNodes: '' });
fakeServer.respond();
expect(spyAjaxRequest.calledOnce).toBeTruthy();
Otro ejemplo de stub para evitar que
se muestre un mensaje de confirmación y comprobar que se ha llamado a dicho
mensaje.
stubOnShow =
U4.testframework.stub(U4.Msg, 'show').yieldsTo('fn', 'ok');
expect(stubOnShow.called).toBeTruthy();
Etiquetas:
jasmine,
javaScript,
sinon,
TDD,
testing
Suscribirse a:
Entradas (Atom)