2009-04-04 13 views
16

Estoy usando el patrón de módulo en Javascript para separar mi interfaz pública de la implementación privada. Para simplificar lo que estoy haciendo, mi código genera un gráfico. El gráfico se compone de varias partes (axises, etiquetas, la trama, la leyenda, etc.) Mi código es el siguiente:Prueba de funciones privadas en javascript

var Graph = function() { 
    var private_data; 
    function draw_legend() { ... } 
    function draw_plot() { ... } 
    function helper_func() { ... } 
    ... 

    return { 
    add_data: function(data) { 
     private_data = data; 
    }, 
    draw: function() { 
     draw_legend() 
     draw_plot() 
    } 
    } 
} 

Algunas personas sólo abogan por probar la interfaz pública de sus clases, lo cual tiene sentido, pero me Realmente me gustaría realizar algunas pruebas para probar cada uno de los componentes por separado. Si arruino mi función draw_legend(), me gustaría que fallara esa prueba, no una prueba para la función pública draw(). ¿Estoy en el camino equivocado aquí?

Podría separar cada uno de los componentes en diferentes clases, por ejemplo hacer una clase de Leyenda. Pero parece una tontería crear una clase para lo que a veces son solo 5-10 líneas de código, y sería más feo porque tendría que pasar un montón de estado privado. Y no podría probar mis funciones de ayudante. ¿Debo hacer esto de todos modos? ¿Debo aspirar y solo probar el sorteo público()? ¿O hay alguna otra solución?

+0

Esto podría ser útil [Cómo probar Unidad funciones privadas en JavaScript] (http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/) – amirnissim

Respuesta

9

No hay forma de acceder a las funciones internas (privadas) desde un ámbito externo. Si desea probar las funciones internas, puede considerar agregar un método público solo para fines de prueba. Si está utilizando algún tipo de entorno de compilación, por ejemplo, hormiga, puede preprocesar el archivo javascript para la producción y eliminar esas funciones de prueba.

En realidad, Javascript es un lenguaje orientado a objetos. Simplemente no es una tipica estadistica.

+5

En realidad, Javascript no está orientado a objetos, está basado en prototipos. Simplemente puede imitar el comportamiento de OO. – pcjuzer

+11

@pcjuzer, Javascript definitivamente está orientado a objetos, simplemente se implementa de forma diferente que los lenguajes de OO clásicos con los que la mayoría de la gente está familiarizada. –

+0

¿Cómo agregaría un método público de prueba sin perder toda la seguridad? –

0

En un lenguaje orientado a objetos, normalmente probará en unidades los protegidos métodos haciendo que la clase de prueba herede de la clase que está probando.

Por supuesto, Javascript no es realmente un lenguaje orientado a objetos, y este patrón no permite la herencia.

Creo que o bien necesita hacer públicos sus métodos, o darse por vencido en la unidad de probarlos.

+0

En C#, un clas derivado no puede acceder a los miembros privados de su clase base. ¿Eso es diferente con otros idiomas? –

+0

En Java también, no se puede acceder a un miembro o método privado por subclases. –

+0

Lo siento, quise decir protegido. –

1

De hecho, es una manera fácil. Puede usar ajax para cargar el script e inyectar una función que expone las funciones privadas. Tengo un ejemplo here que usa qUnit y jQuery. Pero estoy seguro de que lo mismo se puede lograr fácilmente usando Javascript puro.

+0

Esto es un problema si desea probar la versión compilada por cierre (o uglified, etc.). Solo pruebo la versión compilada: si hay un problema con la compilación, necesito saber. –

3

Tengo un problema similar. La solución que surgió no es algo que me guste, pero cumple su función y no hay una mejor solución que pueda encontrar.

function Graph() 
{ 
    this.Test = function _Test(expressionStr) { return eval(expressionStr); } 

    var private_data; 
    function draw_legend() { ... } 
    function draw_plot() { ... } 
    function helper_func() { ... } 
    ... 
} 

Para probar:

var g = new Graph(); 
g.Test("helper_func()") == something; 
g.Test("private_data") == something2 
5

Mi solución es sólo un poco de truco.ejemplo QUnit:

En la parte superior de prueba HTML Qunit he declarado:

var TEST_AVAILABLE = true; 

En la clase comprobable Tengo un fragmento de la siguiente manera:

if(TEST_AVAILABLE){ 
    this.test={ 
     hasDraft:hasDraft, 
     isInterpIdIn:isInterpIdIn, 
     // other private methods 
    }; 
} 

En el QUnit se podía verificar

test("hello booth", function() { 
    var b = new Booth(); 
    ok(b); 
    ok(b.test); 
    ok(!b.test.hasDraft()); 
}); 
+0

similar a la sugerencia aquí http://www.mikeball.us/blog/how-to-make-testable-private-functions-in-javascript – jlarson

+0

@jlarson url parece haber cambiado a http://www.mikeball.us/blog/testable-privado-métodos-en-javascript / –

0

Existe la única opción correcta: Diversas versiones para Te Sting y Producción

1) desarrollo de marca únicas partes

/* test-code */ 
api._foo = foo 
/* end-test-code */ 

2) tira de ellos más tarde ...;)

grunt.registerTask("deploy", 
    [ 
    "concat", 
    "strip-code", 
    ... 

@philwalton ha escrito artículos bellas:

Cuestiones relacionadas