2012/09/01

Automatización de test - eci 2012

Resumen práctico del curso "Generación Automática de Tests Unitarios" (ECI 2012 N2) a cargo de Nazareno Aguirre, Universidad Nacional de Río Cuarto, Argentina


Esta reseña es solo un disparador, no es una guía ni una explicación detallada, es el resultado de hacer la práctica y el examen. Omito cosas importantes que supongo conocidas, pongo el foco en detalles secundarios y mecho con mis opiniones. Aclaro que mi relación con java es meramente académica, carezco de experiencia profesional. Sí tengo experiencia en unit testing, TDD y desarrollo en general.

Lo que se vió en el curso fue diversas maneras de automatizar el testing, ya sea generando tests, generando entrada para los tests o probando la resistencia de los tests.

Mi stack fue:
windowslinux
oracle java 1.7 (ups! la del 0day exploit!!openjdk con JavaSE-1.6 como execution environment para que funcione randoop
eclipse 3.7.2 indigo for java developerseclipse 4.2? juno for java developers
codecover 1.0.1.2
randoop 0.1.0.201107281327
jumble 1.0.0
korat 1.0
korattester 0.0.5 (FAIL)


CodeCover


Herramienta de análisis de cobertura de código.

La idea es que diversos aspectos de un programa como cada linea, cada decisión y cada camino posible sean recorridos por los test. Esta herramienta mide justamente eso.

Hay que habilitar para el proyecto (Propiedades->CodeCover->Enable Code Cover) y seleccionar criterios, luego seleccionar una clase a analizar (right click -> "Use for code coverage measurement") y finalmente ejecutar un test como "CodeCover measurement for junit".

Si hay distintos test cases se pueden agrupar en una suite o ejecutar cada uno separado y luego activar ambos resultados. Al activar (o como se llame) cada resultado, en el código fuente se ve la cobertura o su falta.

Instalación


via repo

Randoop


Herramienta de generación test al azar con feedback.

Para cada método, intenta generar código tal que se pueda llamar a ese método y dependiendo de los resultados, fallas y excepciones declaradas y lanzadas, detecta situaciones de falla y genera código de test para regresiones. Requiere que cada clase tenga un método repOk() que comprueba que el objeto esté en un estado válido. No es necesario que este método haga una validación completa.

Un ejemplo de repOK() para una pila

@CheckRep
public boolean repOk() {
    if (numItems < 0 ) return false;
    if (numItems == 0 && tope != null) return false;
    return true;
}


Uno mas completo que comprueba que el número de items corresponda a la realidad y que no sea una lista con un loop:

@CheckRep
public boolean repOK() {
    int cantidad = numItems;
    Nodo corr = tope;
    while (cantidad>0 && corr!=null) {
        corr = corr.obtenerSiguiente();
        cantidad--;
    }
    return (cantidad==0 && corr==null);   
}



Un ejemplo del código de test generado:

public void test49() throws Throwable {
    myUtils.PilaSobreListasEnlazadas var0 = 

        new myUtils.PilaSobreListasEnlazadas();
    var0.apilar((java.lang.Object)'#');
    java.lang.Object var3 = var0.tope();
    var0.desapilar();
    boolean var5 = var0.esVacia();
    var0.apilar((java.lang.Object)0L);
   
    // Regression assertion (captures the current behavior of the code)
    assertTrue("'" + var3 + "' != '" + '#'+ "'", var3.equals('#'));
   
    // Regression assertion (captures the current behavior of the code)
    assertTrue(var5 == true);
}


Hay que elegir una clase, right click -> Run as Randoop test input, poner un criterio de stop, algunos maximums y ejecutar. En el package/name provisto se generarán los test.


Tiene varias utilidades:

  • Teniendo tests, ver si no hay algún errorcito extra por ahi.
  • A partir de una implementación correcta pero ineficiente, tener una referencia para optimizarla.
  • A partir de una implementación ajena, tener una referencia para reimplementarla. ¡Ups!, ¿no será ilegal?
  • Testear código legacy, aunque con algunas restricciones. Si este código legacy no tiene tests, por algo será, ¿no? Probablemente tenga interdependencias y partes no mockeables que pueden imposibilitar la ejecución. Nada mejor que correr secuencias interminables de código al azar sobre un sistema en producción conectado a una base de datos.


Instalación


Bajar el jar y ponerlo en plugins

Jumble


Herramienta de code mutation.

Lo que hace es dada una clase y su testcase, cambiar en la clase algunas cosas como operadores aritméticos y lógicos y ejecutar el test. Si no falla, considera que está mal el test.

Sólo hay que elegir una clase, right click y "jumble class".

Al usar Parametrized Test Classes, me encontré con un problema. Como resuelve la clase de test por convención de nombres, hay que poner en un solo testcase los test parametrizados y los no parametrizados, lo que produce una ejecución de los tests no parametrizados repetida tantas veces como los parámetros, totalmente innecesaria. Hay una anotación, @TestClass, pero no logré que la respete ni apuntando a uno y otro test ni a una test suite con ambos.

Instalación


bajar el zip y copiar

cp -r jumble_1_1_0/eclipseplugin/plugin-export/jumble eclipse/plugins/

Korat


Herramienta para generar datos de entrada para test exhaustivos acotados.

Supongamos que queremos probar algún método con arrays de 4 posiciones con 4 valores. Se pueden generar todas las combinaciones sin problemas. Ahora bien, si la estructura es más compleja, como un árbol, la cosa se complica pues ya no sólo hay que generar los datos si no la estructura, lo cual produce varios inconvenientes:

  • muchas combinaciones
  • resultados redundantes (si tienen la misma forma, ¿que me importan los nodos en si?)
  • hay estructuras que pueden ser inválidas (loops, desconexiones)
  • pueden haber otros constraints, como que los datos estén ordenados en un árbol binario de búsqueda.

Korat, mediante una invariante y una breve descripción, puede generar estructuras válidas, no redundantes.



La mejor (única) manera que encontré de usar korat es bajar el snapshot del svn y agregar a examples la clase a analizar, luego se llama como en los ejemplo provistos, pero usando nuestra clase.

java -cp korat.jar korat.Korat --class korat.examples.colas.ColaSobreListasEnlazadas --args 4,0,1 --visualize

Los ejemplos son muy claros para estructuras, pero no hallé la manera de poblar los nodos de las estructuras cuando estos usaban objetos genéricos.

En eclipse he agregado korat.jar al build path para autocompletar con todo éxito.

Intenté usar un plugin de korat para eclipse, korattester, pero no funciona.

Instalación


svn co https://korat.svn.sourceforge.net/svnroot/korat/trunk/ korat


Pex


Este es el que menos pude investigar, ya que es para .NET.

No tengo nada que decir, sólo que pex4fun es muy divertido, si sos nerd.

Referencias


[eci n2] http://www.dc.uba.ar/events/eci/2012/cursos/aguirre

[docente]  http://dc.exa.unrc.edu.ar/staff/naguirre/Pagina_personal_de_Nazareno_Aguirre/Principal.html

[practica] https://sites.google.com/site/genunittests/


[java] http://www.oracle.com/technetwork/java/javase/downloads/index.html

[eclipse] http://www.eclipse.org

[codecover] http://codecover.org/

[codecover eclipse] http://update.codecover.org/

[randoop] http://code.google.com/p/randoop/

[randoop eclipse] http://randoop.googlecode.com/hg/plugin.updateSite/

[jumble] http://jumble.sourceforge.net/

[korat] http://korat.sourceforge.net/

[korattester] http://code.google.com/p/korattester/

[pex] http://research.microsoft.com/en-us/projects/pex/

[pex for fun] http://www.pexforfun.com

[pex standalone download] http://research.microsoft.com/en-us/downloads/d2279651-851f-4d7a-bf05-16fd7eb26559/default.aspx

2012/07/29

Privacidad y buenas intenciones


BABYLSCRIPT


Cuando me dispuse a criticar la iniciativa de traducir el lenguaje de programación javascript a una docena de idiomas [babylscript], consulté a diversas personas intentando traer agua a mi molino o al menos quitar las piedras y me encontré con que el agua vino con piedras y como no soy un experto en lingüistica, sociología, sicología ni aprendizaje y sólo tengo mi experiencia propia en varios lenguajes y paradigmas de programación, no puedo hacer una Gran Teoría. [Argerich][docentes][embed32]

Mi idea era decir algo asi como "Si una persona tiene dificultad en comprender un lenguaje de programación, no pienso que sea por los símbolos del lenguaje, aunque pueda ayudar, sin duda es más sencillo para alguien que usa un alfabeto latino que para el resto, pero aún así, la dificultad principal está en comprender la programación.", que es algo que a mi me parece razonable pero no puedo sustentar mediante opiniones expertas.

Esto me fuerza a ir a las piñas sin pensar mucho, al grano. Cito: "Babylscript allows people to write programs in a mix of different languages. A programmer can take a library written in French, mix it with their own program written in Spanish, and use code snippets they found on a Chinese help forum"


Asi que ahora no sólo hay que comprender un lenguaje, sino... ¡doce! ¿Cómo hago para saber que 
 
если
إذا
যদ্যপি
如果
अगर
もし
만약
dacă
wenn
se
si
if

son todo lo mismo? Yo entiendo sólo los tres últimos, si el código viene en coreano, no tengo ninguna manera de saber que hace, es como si me dieran código objeto, ya compilado. Esto no sirve para integrar, sólo para fragmentar. A medida que las comunidades crezcan, comenzarán a separarse. No quiero ponerme bíblico, pero es realmente Babel, aunque el castigo se recibe al poner el cimiento, no al alcanzar el cielo.

Lo que el párrafo citado dice es "usá código que suponés que hace lo que dice la documentación", pero ¿en qué idioma está esa documentación?, tendríamos que establecer un idioma común para la documentación, para poder compartir nuestros componentes.


Aunque a muchos no les guste, el idioma inglés es el idioma común al menos de la tecnología. ¿Es eso justo y democrático? Pues a aprender chino.

Sin embargo, no se puede negar que esta iniciativa tiene algo bueno, se acabó eval().


Pero...


...supongo que a esta altura cualquiera se preguntará que tiene que ver que unos pobres infelices reescriban javascript en un montón de idiomas con el título "privacidad". ¿Por que me estoy ensañando con gente bien intencionada con la cual ni siquiera me he contactado (ni lo voy a hacer) para advertirles del peligro que implican para la humanidad programadora?

Caso dos


En el año 1930, en Holanda se hizo un censo y uno de los datos era religión. La intención de los encuestadores era poder dar entierro de acuerdo a sus creencias a quien muriera careciendo de parientes [censo]. Cuando en el año 1940 los alemanes invadieron, se apoderaron de este censo y lo usaron para sus fines. Vemos aqui de modo mucho más concreto y "definitivo" como las buenas intenciones pueden traer consecuencias imprevistas y desagradables.

Caso tres: Amo de tus silencios, esclavo de tus twits


Para este caso, del cual disto tanto como de los otros ser descubridor, no voy a citar fuentes ya que sobran. 

Cuando al hablar decís algo, ya es tarde, lo has dicho, quienes te escucharon lo tienen en sus mentes, quizas se olviden, probablemente. De todos modos, la gente tergiversa sus recuerdos, no es tan terrible. Uno debe cuidar lo que dice, pero no podemos estar todo el día tan pendientes, hay que vivir.

Cuando escribís algo en papel (sin computadora de por medio), aunque es más fidedigno, ese papel y sus fotocopias se pueden perder, deteriorar, son difíciles de hallar y de relacionar. Hay que prestar un poquito más de atención, no firmar cheques en blanco. De todos modos, el escribir en papel permite tomarse su tiempo, reflexionar sobre lo que se va a decir.

Escribir en la computadora es parecido, salvo que no tenés nunca certeza de que no haya un bichito tomando nota o que el editor que usas no deje temporarios que luego puedan recuperarse.

Cuando das el salto final y ponés tu información en Internet, la que nunca olvida, perdés completamente el control sobre ella y además puede ser increiblemente fácil de encontrar.

Cuando ponés información personal en tu blog, facebook, twitter, le estás dando a la posteridad la capacidad de conocerte, lo cual en términos filosóficos y sensibles podría ser bueno, lograste una cierta trascendencia, salvo que, como dijo Syndrome: "Everyone can be super! And when everyone's super... [chuckles evilly] no one will be." [Syndrome]

No sólo la posteridad te conoce, tambien te conoce la banda de criminales informáticos que te hace un spear phishing, la de criminales comunes que te vacía la casa cuando tu GeoTrackMe.com dice que estás ausente.

No estoy cuestionando la actividad profesional o académica, sería incoherente de mi parte estar escribiendo esto. Se hace una evaluación de riesgo, que ganás y que perdés al poner tu cv en linkedin, al opinar en un foro profesional. En esos casos obtener trabajo en el futuro, compartir información o enseñar algo, que es la mejor manera de aprender.

Cuando dás tu ubicación, tus gustos y relaciones personales, supongo que lo hacés por relaciones personales, para alimentar tu ego, para no ser menos que el resto. Por mi está ok, pero ¿hiciste una evaluación de riesgo?

Quien no me crea, que use Internet contra si mismo, a ver que resultados consigue.


Referencias:

  • [babylscript] http://www.babylscript.com/
  • [Docentes - mi pregunta] "Se podría afirmar que es más fácil cambiar de lenguaje (Haskell <-> Erlang, C <-> Pascal, Asm Pic <-> Asm 360, Java <-> C++) que de paradigma (bajo nivel, estructurado, objetos, funcional)?"

  • [embeb32 - mi pregunta] "¿Se podría afirmar que quien aprende a programar en assembler de cualquier arquitectura tiene menos dificultad en cambiar de arquitectura que en cambiar de paradigma? Por ejemplo pasar de Asm 360 a Asm Pic vs. pasar de assembler a programación funcional." https://groups.google.com/forum/?hl=es#!topic/embebidos32/ckFwftHsd5U
  • [Argerich - correspondencia privada] "En base a mi filosofia de que los paradigmas de programacion en realidad no existen y son solo una excusa para vender libros, cursos y demas cuestiones diria que no. Desde la epoca del Fortran que programar es meter una linea de codigo debajo de otra, es el area de la computacion mas estancada por lejos."
  • [censo holanda] http://en.wikipedia.org/wiki/History_of_the_Netherlands_%281939%E2%80%931945%29#High_Jewish_death_toll
  • [censo] Lamentablemente de esto no tengo la cita precisa, pués me parece que lo leí hace mucho en algún diario, pero no recuerdo bien.  Me contó alguien que lo vió en un documental sobre Internet de la BBC, emitido en Film&Arts, ya lo voy a encontrar.
  • [Syndrome] http://www.imdb.com/title/tt0317705/quotes