¿Cómo escribo pruebas unitarias para robots (y otros dispositivos mecánicos)?

22

Soy miembro del club de robótica de mi escuela secundaria y soy responsable de programar el robot. Una sugerencia que sigo escuchando de varios adultos es que debería escribir pruebas unitarias para ayudar a validar mi código. La base del código se está volviendo un poco grande, y estoy de acuerdo en que las pruebas unitarias serían realmente útiles para ayudarme a detectar errores más rápido.

Sin embargo, no estoy completamente seguro de cómo podría lograr esto. Hasta donde sé, la prueba de la unidad se realiza tomando una función (o un subsistema del código) y alimentándola con un conjunto de entrada para asegurarse de que salga con la misma salida cada vez. El código que tengo actualmente no hace un gran procesamiento de datos, sino que manipula directamente los componentes de hardware en el robot. La mayor parte de la complejidad proviene de asegurarse de que los componentes electrónicos sean sólidos, que el código en este momento coincida con el hardware real del robot, etc. Muchas veces, solo puedo ver si hay un problema al cargar el código en el robot, e intentando ejecutarlo.

Por extensión, ¿cómo pueden escribirse las pruebas unitarias para el código destinado a operar cualquier dispositivo mecánico? Me parece que solo puede detectar errores al observar físicamente el funcionamiento de la máquina.

¿O simplemente estoy malinterpretando cómo deberían funcionar las pruebas unitarias?

( Si es importante, aquí está el código , está escrito en C ++ y estoy participando en FRC )

Michael0x2a
fuente

Respuestas:

21

Tendrá que burlarse de la capa de hardware para hacer esta prueba. La idea es que en lugar de que su código hable con el hardware real, hable con una versión falsa del hardware que pueda controlar y luego usar para verificar que su código funcione correctamente.

Lamentablemente, hay algunos problemas que debes superar:

  • Burlarse de cosas en lenguajes de nivel relativamente bajo es más difícil (y por lo tanto, mucho más trabajo)
  • Burlarse de cosas a nivel de hardware es más difícil (y, por lo tanto, mucho más trabajo)

Además, la mayor parte del valor de las pruebas unitarias automáticas proviene de poder ejecutar sus pruebas en cualquier momento para detectar errores de regresión durante largos períodos de tiempo después de escribir el código original. Con este tipo de competiciones, su código no se utilizará en absoluto una vez finalizado el concurso, por lo que realmente no obtendrá la mayor parte del valor de las pruebas. Y teniendo en cuenta lo difícil que sería agregar pruebas a su caso particular, podría ser mejor utilizar su tiempo para hacer pruebas manuales y centrarse en las características del concurso.

Oleksi
fuente
1
Buena respuesta. Especialmente el bit sobre el hecho de que el código no se usará después de la competencia, y que el gran beneficio de las pruebas unitarias automáticas llega mucho después de que se hayan escrito las pruebas. Puede considerar automatizar algunas de sus pruebas en el caso en que se encuentre ejecutando la misma prueba una y otra vez; pero hasta que esto suceda, no tiene mucho sentido.
Dawood dice que reinstalar a Monica el
No es necesario burlarse del hardware en absoluto. Si el robot tiene un registro, ejecute el programa de prueba y observe los registros. La prueba final necesita observación "girar a la izquierda" en el registro debe corresponder al robot que gira a la izquierda. Deberá escribir un arnés de prueba para burlarse de los dispositivos de entrada: enganche el código del dispositivo de entrada lo más cerca posible de la capa de hardware
Mattnz
44
@DavidWallace Como un poco de pensamiento para pensar, cuando se usa TDD / BDD, los beneficios de las pruebas unitarias ocurren de inmediato. En primer lugar, permitiendo que el código se refactorice con confianza de inmediato, y en segundo lugar, alentando la implementación para que se limite a la implementación mínima necesaria para satisfacer las pruebas.
S.Robins
44
@mattnz mala idea, y sé por experiencia. ¿Qué pasa si el código bajo prueba falla muy, muy duro y el brazo del robot se estrella contra la pared, arruinando una pieza de hardware xxxx $?
stijn
2
@mattnz: Nuestros robots miden aproximadamente 2 pies por 3 pies por 4 pies y pesan alrededor de 150 libras. El kit / registro cuesta 5 mil dólares cada año, y generalmente recaudamos otros 5 a 10 mil para comprar piezas adicionales. El peor de los casos probablemente costaría más de $ 10;)
Michael0x2a
10

Puedo pensar en un par de cosas que deberás considerar. La primera es hacer que su capa de acceso de hardware sea lo más delgada posible, incluso si eso significa crear una capa de tipo envoltorio básico para ella. Esto le ofrece un par de ventajas. La primera es que le permite aislar los comportamientos específicos de hardware de su código del acceso de hardware en sí, lo que significa que puede probar todo hasta la parte inferior de sus comunicaciones de hardware sin necesidad de acceder al hardware en sí.

Por ejemplo, si necesita diseñar un protocolo de señalización basado en I2C, puede probar que su código está generando las señales I2C correctas sin necesidad de conectar el hardware a sus pruebas.

Para las llamadas al hardware real, puede probar que se están comportando correctamente burlándose de su capa de hardware, y aquí es donde mantener una capa de hardware muy delgada realmente vale la pena, porque puede reducir su simulación a la necesidad de manejar solo las funciones mínimas requeridas para en realidad se dirige al hardware, pero no necesariamente necesita probar las señales individuales, ya que toda su señalización debería haber sido comprobable en un nivel superior. Esto significa que usa su simulacro para verificar que las llamadas se realicen a métodos de hardware específicos que hacen que sus señales se envíen al hardware. Si necesita sondear su hardware, entonces su simulación debe ser capaz de activar eventos o métodos en su código solamente, porque nuevamente, su señalización de retorno debe manejarse en una capa superior.

Básicamente, esto encaja con lo que dijo Oleksi en su respuesta , ya que generalmente es más trabajo burlarse de las cosas a nivel de hardware, sin embargo, no es tan difícil si se mantiene en la capa más mínima posible de código mínimo / llamada que puede hacer para el hardware.

Cuando tenga un código que pase todas sus pruebas, aún necesitará ejecutar una serie de pruebas manuales para asegurarse de haber conectado todo correctamente en su capa de hardware.

La otra cosa que viene a la mente, aparte de la burla y la estratificación, es usar una práctica de desarrollo de prueba primero. Esencialmente, codifica sus requisitos como criterios de prueba y basa su implementación en sus pruebas. Esto lo ayudará a asegurarse de mantener su código de implementación al mínimo, al tiempo que garantiza que todos sus casos de prueba impulsen sus esfuerzos de desarrollo. Al no perder demasiado tiempo en otro código potencialmente no crítico que podría sentirse tentado a hacer "solo porque", la prueba primero lo ayuda a mantenerse enfocado y facilitará el cambio de código a medida que depura, al igual que el uso de sus pruebas unitarias y simulacros. La depuración de errores de software a través del hardware es notoriamente complicada y absorbe grandes cantidades de tiempo que sería mejor gastar en otras tareas.

S.Robins
fuente
2

Puedo decirte cómo lo hacen en simuladores de vuelo

En primer lugar, solo obtendrá la mitad de la respuesta si hace esta pregunta solo a los programadores, por lo que probablemente debería publicar esto en http://electronics.stackexchange.com mientras lo hace.

No he trabajado con robots, pero pasé 5 años haciendo hardware en simuladores de vuelo para poder decirte cómo funciona su arquitectura.

La capa de hardware es tonta

Contiene una interfaz básica donde puede ajustar valores simples de entrada / salida y establecer puntos de interrupción de interpolación para señales analógicas. Cuando trabaje con hardware 'nuevo', todo funcionará como se espera con poca o ninguna calibración, pero con el tiempo las piezas sufrirán desgaste mecánico y deberán ajustarse.

La calibración es una tabla simple que contiene un rango seccionado entre los valores mínimo / máximo. Para medir la entrada en estos, generalmente se utiliza un servo (por ejemplo, un potenciómetro lineal, transductor, acelerómetros, etc.). O, en el caso de la instrumentación, simplemente juzga la precisión visualmente y ajusta hasta que se calibra.

La capa de software es lo opuesto

Todo es complejo e interconectado, por lo que es importante aislar algunas variables para probar la funcionalidad. No es necesario preocuparse por pensar en escenarios porque es mucho más fácil ejecutar algunos escenarios realistas donde puede recopilar datos. Cuando ejecuta las pruebas, básicamente está midiendo los datos almacenados con la salida actual.

En un simulador de vuelo, esto se conoce como QTG (Guía de prueba de calificación). En esencia, traza los datos en una cuadrícula 2D donde una dimensión es el tiempo y la otra es la salida.

Lo creas o no, esa es la esencia de cómo desarrollan los modelos. Un avión real está equipado con una tonelada de sensores y vuela haciendo escenarios controlados. Debido a que todos los controles pueden manejarse sin interacción humana, la computadora ejecuta las pruebas (es decir, el sim vuela) y se comparan los datos.

Aunque la robótica se crea en una escala muy diferente, los principios son los mismos. El enfoque tradicional es cortar completamente las capas de hardware y software para que ambas puedan probarse individualmente. La entrada de hardware se recopila a través de servos y se configura a través de una interfaz independiente. La entrada de software se puede configurar / leer midiendo y comparando de forma independiente la señalización que de otro modo iría al hardware y trazándola contra los datos "buenos" conocidos.

Las pruebas en sí mismas no necesariamente tienen que ser complejas siempre que los resultados sean predecibles, medibles y reproducibles.

Evan Plaice
fuente
1

Como se dijo anteriormente, burlarse de las partes de hardware. Como ejemplo, si tiene una interfaz para el robot, puede heredar de esa interfaz y luego realizar implementaciones de código auxiliar simples. Luego puede hacer una prueba de que la implementación del código auxiliar se ha llamado como se esperaba. Si eso es funciones esperadas o parámetros esperados.

Martiert
fuente