2012-02-28 14 views
6

Me está costando mucho tiempo entender cómo configurar un objeto que me permita probar mis llamadas jQuery. No necesito burlarme de ninguna llamada Async ni nada, solo uso básico. Así que permítanme puse mi función que quiero probar (truncada por simplicidad):Burlarse de jQuery para probar el uso básico

listGamesCallback : function(data) { 
    var gameList = $("#gameList select"); 

    gameList.empty(); 

    $.each(data, function() { 
      var newOption = $('<option>', {value : this.gameId }); 
      newOption.text(string); 
      newOption.data("isJoinable", isJoinable); 

      // Add it to the list 
      gameList.append(newOption); 
    }); 


} 

necesito para burlarse del jQuery aquí para unidad de prueba de este método, pero soy incapaz de encontrar la manera de hacer esto en javascript Incluso sin jsMockito, no sé cómo crear un objeto con las propiedades que jQuery tiene en esta situación. Cualquier ayuda con esto sería apreciada.

Estoy usando jsTestDriver, jsHamcrest, jsMockito y jQuery. Sin embargo, un enfoque generalizado para crear un objeto $ que tenga estas propiedades también sería asombroso. ¡Gracias!

Para aquellos que preguntaron, esto es lo que se me ocurrió que parecía funcionar un poco ... pero no entiendo por qué.

var saved$ = $; 

var mockContruct = mockFunction(); 
var mockedGamelist = mock(jQuery); 
var mockedOption = mock(jQuery); 

mocked$ = (function() { 
    var test = function(name) { 
     var args = jQuery.makeArray(arguments); 
     return mockContruct.call(test, args); 
    }; 

    $.extend(test, $); 

    // This is what confuses me. This worked, but it's wierd 
    // It allows me to use the regular jQuery functions like 
    // $.each, while returning mocked objects when selectors are used. 
    test.prototype.constructor = test; 

    return test; 
})(); 

$ = mocked$;  

when(mockContruct).call(anything(), hasItem(containsString("#gameList"))) 
    .thenReturn(mockedGamelist); 

when(mockContruct).call(anything(), hasItems(containsString("<option>"), both(object()).and(hasMember("value")))) 
     .thenReturn(mockedOption); 

headerFunctions.listGamesCallback([ { 
    gameId : 1, 
    isWhitesTurn : false, 
    isGameOver : false, 
    whiteUserName : "foobar", 
    blackUserName : "barfoo" 
} ]); 

JsMockito.verify(mockedGamelist).empty(); 
JsMockito.verify(mockedGamelist).append(mockedOption); 

$ = saved$; 
+0

Sería útil si también proporcionó su código de prueba. :) – alpian

+0

Ok, perdón por la respuesta tardía, pero me han reasignado por lo que esta obtuvo una prioridad más baja. Tengo una forma complicada de ejecutar la prueba que edité en la pregunta. No está escrito muy bien porque no entiendo muy bien cómo jQuery hace lo que hace. – CrazyBS

+0

La prueba que ha escrito realmente no prueba nada más que su código se ejecuta. También puede contaminar otras pruebas con problemas si falla porque no restaurará $ si falla. Creo que aún te estás perdiendo el objetivo de estas pruebas: debes escribir una prueba del ** comportamiento ** que esperas de tu código, no los detalles de cómo lo hace. Debería intentar escribir una prueba que solo se centre en probar que gameList tiene opciones X con cualquier valor en ellas una vez que se haya ejecutado su función. – alpian

Respuesta

1

Ok, aquí lo que se me ocurrió es que hace el trabajo con una configuración mínima. .extend es completamente necesario aquí para que el objeto jQuery esté configurado correctamente. Esto le permite burlarse del constructor para devolver objetos jQuery simulados que puede usar para ejecutar sus pruebas. Como espía, jQuery funcionará como se espera en todas las situaciones, excepto cuando desee que haga otra cosa. Aquí está:

TestCase("HeaderTest", { 
    testListGamesCallback : function() { 
     var saved$ = $; 

     $ = $.prototype.construct = jQuery.extend(spy(jQuery), jQuery); 

     var mockGameList = mock(jQuery); 
     when($)(containsString("#gameList")).thenReturn(mockGameList); 

     headerFunctions.listGamesCallback([ { 
      gameId : 1, 
      isWhitesTurn : false, 
      isGameOver : false, 
      whiteUserName : "foobar", 
      blackUserName : "barfoo" 
     } ]); 

     verify(mockGameList).empty(); 
     verify(mockGameList).append(object()); 

     $ = saved$; 
    } 
}); 

La advertencia de esta solución es que burla que no sea el constructor de todo es un poco complicado. Deberá configurar cada función individual que desee simular, luego programar el comportamiento. Entonces:

$.each = mockFunction(); 
when($.each)(...matchers...).thenReturn(...); 

Pero todavía permite probar lo que necesita.

0

No estoy seguro si entiendo lo que quieres decir, pero si desea crear 'datos' para usted ejemplo, este es el método que sé:

var data = [ { id : 1 , name : 'foo' } , { id : 2, name : 'bar' ] ​ 

pero - si desea crear una lista de opciones, de lo que necesita un código par de correcciones: ver http://jsfiddle.net/7MMap/

var data = [ { gameId : 1 , name : 'foo' ,isJoinable:true} , { gameId : 2, name : 'bar' ,isJoinable:false}] 

    listGamesCallback = function(data) { 
    var gameList = $("#gameList select") 
        .empty(); 

    $.each(data, function(i,d) { 
      var newOption = $('<option>', {value : d.gameId }) 
      .text(d.name) 
      .data("isJoinable", d.isJoinable); 

      // Add it to the list 
      gameList.append(newOption); 
    }) 
      }; 

listGamesCallback(data); 
+0

En realidad, la función jQuery.each() le permite acceder al valor directamente con 'this'. Y todos esos .text(). Data() complica el burlarse y en mi humilde opinión lo hace menos legible. Pero eso es solo opinión. Gracias por su respuesta bien formateada. Todavía estoy buscando burlarme de jQuery. – CrazyBS

0

burlando de jQuery no es lo que es para burlona. Solo debe burlarse de los colaboradores de su objeto. jQuery te proporciona algunas utilidades, no es un colaborador y, por lo tanto, no se debe burlar.

Lo que está colaborando aquí es el DOM, o algún objeto intermedio entre su código y el DOM. data es un objeto de valor y simplemente se puede crear en su prueba como sugiere Avi.

En mis pruebas de JS, no me burlo del DOM, utilizo el DOM real y estoy seguro de derribar todo lo que he creado entre las pruebas, y esto parece funcionar bastante bien.

+0

Estoy de acuerdo con mi exceso de pruebas en esta situación. Sin embargo, mi pensamiento era que, dado que quiero que mi prueba esté lo más aislada posible, no quiero que jQuery realmente haga algo, solo necesito verificar que se usó. Sin embargo, esto requiere que jQuery siempre se use para pasar la prueba. Entonces tienes un punto. – CrazyBS

+0

¿Puedo burlarme del DOM? – CrazyBS

+0

Bueno, por supuesto que puedes **, pero en tu caso, en su prueba, solo añadiría un REAL select con ID gameList al REAL DOM, y luego ejecutaría tu función, y luego, después de ejecutarla, probaría (por ejemplo con selectores CSS) que el DOM se ve como debería: luego, limpie después de usted mismo eliminando esa selección. Olvídate de tratar de burlarse de jQuery, es una utilidad, y no deberías necesitar hacer eso :). – alpian

1

Como una extensión de la respuesta de alpian, puede crear elementos DOM sin tener que agregarlos a la página.Hacer sus funciones JS toman los elementos relevantes como parámetros:

listGamesCallback : function(data, gameListSelectElem) { 
    var gameList = $(gameListSelectElem); 
    ... 

y prueba de ellos, así:

var fakeSelect = $('<select>'), 
    data = ...; 

listGamesCallback(data, fakeSelect[0]); 

equal(fakeSelect.find('option').length, 1, 'must have exactly 1 option'); 
... 

La última línea de código anterior es para qUnit. Toma lo que necesites, el punto es decir que puedes pasar un elemento DOM que nunca se agregó a la página y luego investigar ese elemento DOM usando jQuery para encontrar si fue manipulado correctamente.