Mockeando Window.location

Estoy en un proyecto donde tengo que interactuar con servicios RestFul desde javascript. El problema que tengo es que estos servicios están aún en desarrollo por lo que cuando me toca trabajar con ellos puede que estén o no disponibles.

Para evitar detener mi trabajo cuando los servicios no están disponibles he decidido que los test trabajen con mocks. Hace unos días me tocó hacer un test para chequear un método que internamente hacía uso de window.location.

Hay muchas soluciones disponibles para testear nuestro método, veamos una de ella:

  1. var MyNamespace = new function()
  2. {
  3.     this.MyObject = function(win)
  4.     {
  5.         var __win = win;
  6.  
  7.         this.NavigateTo = function(p1, p2)
  8.         {
  9.             var __url = "http://www.google.com/?q=" + p1 + "&s=" + p2;
  10.             __win.location.href = __url;
  11.         };
  12.     };
  13. };

Este sería nuestro objeto en javascript el cual contiene un método llamado NavigateTo y al que le pasamos dos parámetros para formar una url.

Probar este método es muy fácil: (usaremos qunit por su cómoda integración con ReSharper)

  1. test("Window location", function ()
  2. {
  3.     var __winMock = { location: { href: "" }};
  4.     var __myObj = new MyNamespace.MyObject(__winMock);
  5.  
  6.     __myObj.NavigateTo('abc', 'def');
  7.  
  8.     window.equal("http://www.google.com/?q=abc&s=def", __winMock.location.href, "is ok");
  9. });

Nuestro test pasa sin problemas.

moc-1

En el momento en que necesitemos que nuestro objeto trabaje con el objeto real, solo tenemos que pasar el window en el constructor.

  1. var __myObj = new MyNamespace.MyObject(window);

Otra solución y mi preferida, es encapsular la llamada a window.location.href en una función que podamos usar desde cualquier parte en nuestro proyecto. Luego solo tendríamos que mockear la función y testear que todo esté correcto.

  1. var MyNamespace = new function ()
  2. {
  3.     this.MyObject = function ()
  4.     {
  5.         this.NavigateTo = function (p1, p2)
  6.         {
  7.             var __url = "http://www.google.com/?q=" + p1 + "&s=" + p2;
  8.             Utils.Browser.Navigate(__url);
  9.         };
  10.     };
  11. };
  12.  
  13. var Utils =
  14. {
  15.     Browser: new function()
  16.     {
  17.         this.Navigate = function (url)
  18.         {
  19.             window.location.href = url;
  20.         };
  21.     }
  22. };

Aquí ya no estamos falseando el objeto window sino que encapsulamos su utilización dentro de un objeto Browser que contiene un método llamado  Navigate.

Para testear el ejemplo anterior, vamos a usar Sinon y su pluging para qunit. Como estamos trabajando con ReSharper para las pruebas, debemos indicar la referencia a estos frameworks en nuestro js de pruebas.

  1. /// <reference path="/resources/sinon-1.5.2.js"/>
  2. /// <reference path="/resources/sinon-qunit-1.0.0.js"/>

Ya con esto podemos crearnos nuestro test:

  1. test("Window location", function ()
  2. {
  3.     var __myObj = new MyNamespace.MyObject();
  4.  
  5.     var __mock = sinon.mock(Utils.Browser);
  6.     __mock.expects("Navigate").once().withArgs("http://www.google.com/?q=abc&s=def");
  7.  
  8.     __myObj.NavigateTo('abc', 'def');
  9.  
  10.     __mock.verify();
  11. });

y el resultado…

moc-1

Lo que me gusta de este método respecto al anterior es que no tenemos necesidad de falsear un objeto nativo del DOM. Por el contrario, lo que hacemos es mokear un objeto nuestro y testear su funcionalidad.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *