Pregunta

Para fines de pruebas unitarias, necesito simular una respuesta de red.La respuesta es normalmente un flujo de bytes, almacenado como un const vector<uint8_t>.Sin embargo, para la prueba unitaria, me gustaría producir el vector con datos codificados en el archivo CPP o leídos de un archivo en la misma solución.Los datos de mi ejemplo son de aproximadamente 6 kb.¿Cuál es la orientación general sobre dónde colocar los datos cuando se utilizan? prueba de google?

¿Fue útil?

Solución

Quizás (a) necesite una gran secuencia de datos para algún papel en el que los casos de prueba simplemente lo lean.Estos también pueden ser datos globales (de clase), conconst acceso.

Quizás (b) necesita una gran secuencia de datos para algún papel en el que los casos de prueba lo leerán y modificarán o destruirán.Esto debe ser reninicializado por caso de prueba y no tieneconst acceso.

Quizás ambas cosas.En cualquier caso, una implementación de GoogleTest convencional usaría una accesorio de pruebaPara encapsular la adquisición de los datos, lo adquiriría en la implementación del accesorio virtual Setup() Función de miembros y acceder a él a través de un método Getter del accesorio.

El siguiente programa ilustra un accesorio que proporciona datos mutables por caso y datos constantes globales adquiridos de los archivos.

#include <vector>
#include <fstream>
#include <stdexcept>
#include "gtest/gtest.h"

class foo_test : public ::testing::Test
{
protected:
    virtual void SetUp() {
        std::ifstream in("path/to/case_data");
        if (!in) {
            throw std::runtime_error("Could not open \"path/to/case_data\" for input");
        }
        _case_data.assign(
            std::istream_iterator<char>(in),std::istream_iterator<char>());
        if (_global_data.empty()) {
            std::ifstream in("path/to/global_data");
            if (!in) {
                throw std::runtime_error(
                    "Could not open \"path/to/global_data\" for input");
            }
            _global_data.assign(
                std::istream_iterator<char>(in),std::istream_iterator<char>());
        }
    }
    // virtual void TearDown() {}   
    std::vector<char> & case_data() {
        return _case_data;
    }
    static std::vector<char> const & global_data() {
        return _global_data;
    }

private:
    std::vector<char> _case_data;
    static std::vector<char> _global_data;

};

std::vector<char> foo_test::_global_data;

TEST_F(foo_test, CaseDataWipe) {
  EXPECT_GT(case_data().size(),0);
  case_data().resize(0);
  EXPECT_EQ(case_data().size(),0);
}

TEST_F(foo_test, CaseDataTrunc) {
  EXPECT_GT(case_data().size(),0);
  case_data().resize(1);
  EXPECT_EQ(case_data().size(),1);
}

TEST_F(foo_test, HaveGlobalData) {
  EXPECT_GT(global_data().size(),0);
}


int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Para el caso (a), también podría considerar adquirir los datos en un configuración globalfunción miembro mediante subclasificación ::testing::Environment, pero no veo ninguna razón general para preferir hacerlo de esa manera.

... ¿O codificarlo?

Luego, a la cuestión de si se debe mantener los datos de prueba en un archivo o codificarlo en la fuente de prueba. Los lectores que estén contentos en este punto sólo se aburrirán de ahora en adelante..

Como un problema general, esto es una cuestión de juicio en las circulaciones y no creo que el uso de Googletest sean materialmente las escalas.Creo que la principal consideración es: ¿Es deseable poder variar un elemento de datos de prueba sin reconstruir la prueba de suite?

Digamos que la reconstrucción del conjunto de pruebas para variar este elemento es un costo no desplegable y anticipa que el contenido del artículo variará en el futuro independientemente del código de prueba asociado.O puede variar, independientemente del código de prueba asociado, para diferentes configuraciones del sistema bajo prueba.En ese caso, mejor obtenga el elemento de un archivo u otra fuente que se pueda seleccionar mediante parámetros de tiempo de ejecución del conjunto de pruebas.En googletest, subclases class ::testing::Environment es una instalación diseñada para la adquisición parametrizada de recursos de la suite de prueba.

Si en realidad El contenido de un elemento de datos de prueba se combina libremente con el código de prueba asociado, entonces es muy poco probable que la codificación dura en los casos de prueba sea una opción prudente.(Y los archivos de prueba, a diferencia de otros tipos de configuradores de tiempo de ejecución, tienen la valiosa propiedad de que pueden controlarse la versión en el mismo sistema que el código de origen).

Si el contenido de un elemento de datos de prueba es Completado firmemente con el código de prueba asociado, estoy sesgado para codificarlo en lugar de extraerlo de un archivo de datos.Simplemente parcial, no dogmáticamente comprometido.Tal vez su conjunto de pruebas emplea instalaciones de biblioteca robustas para inicializar los datos de pruebas de API públicas de, por ejemplo, archivos XML que también están conectados a la gestión de pruebas y los sistemas de gestión de defectos.¡Bien!

Supongo que es claramente deseable que si un archivo de datos de prueba es un recurso de prueba primario, uno que el conjunto de pruebas no puede generar, entonces su contenido debe ser los datos textuales que un mantenedor competente puede comprender y manipular fácilmente.En este entorno, por supuesto, consideraría que una lista de constantes hexadecimales C/C ++, por ejemplo, es datos textuales - Es el código fuente.Si un archivo de prueba contiene datos binarios o desalentamente orientados a la máquina, entonces el conjunto de pruebas debe contener mejor los medios de producción a partir de recursos primarios legibles.A veces es inevitable que una suite de prueba dependa de binarios "arquetípicos" de origen externo, pero casi inevitablemente implican el sombrío espectáculo de los ingenieros de prueba y los fijadores de insectos que se vuelven grises frente a los editores hexagonales.

Dado el principio de que los datos de la prueba primaria deben ser legibles para los mantenedores, podemos tomarlo como una norma de que los datos de la prueba primaria serán "algún tipo de código":Será libre de lógica, pero será el tipo de cosas textuales que los programadores están acostumbrados a la topografía y la edición.

Imagine que se requiere una secuencia particular de 4096 enteros sin firmar de 64 bits (la tabla Big Magic) para probar su software y está muy casado con el código de prueba asociado.Podría estar codificado como una enorme lista de inicializador de vector o matriz en algún archivo fuente del conjunto de pruebas.Podría extraerse mediante el conjunto de pruebas de un archivo de datos mantenido en formato CSV o en líneas emocionadas por CSV.

Para la extracción de un archivo de datos y contra la codificación dura, se puede instar (según la respuesta de Andrew McDonell) que esto valorablemente logra un desenredado de las revisiones al BMT de las revisiones de otro código en el mismo archivo fuente.Del mismo modo, se podría instar a que cualquier código fuente que enmarque enormes inicializaciones literal tiende a ser inseguible y, por lo tanto, una responsabilidad de mantenimiento.

Pero ambos puntos pueden contrarrestarse con la observación de que la declaración definitoria del BMT podría codificarse en un archivo fuente propio.Podría ser una política de revisión de código para el conjunto de pruebas que las inicializaciones de datos de pruebadebe estar tan codificado, y tal vez en archivos que se adhieran a una convención de nomenclatura distintiva.Una política fanática, sin duda, pero no más fanática que una que insista en que todos los inicializadores de datos de prueba deben extraerse de los archivos.Si un mantenedor está obligado a examinar el BMT en cualquier archivo que lo contenga, no tendrá diferencia si la extensión del archivo es .cpp, .dat o lo que sea:Lo único que importa es la comprensibilidad del "código".

Para la codificación dura y contra la extracción de un archivo de datos, se puede instar a que la extracción de un archivo de datos debe introducir una fuente de fallas potenciales irrelevantes en casos de prueba, todos los No debería suceder Errores que podrían derrotar a la lectura de los datos correctos de un archivo.Esto impone una sobrecarga en el desarrollo de la prueba para efectuar una distinción correcta y clara entre las fallas genuinas de las pruebas y las fallas para adquirir los datos de prueba del archivo, y diagnosticar claramente todas las causas posibles de este último.

En el caso de los marcos googletest y comparablemente funcionales, este punto puede ser contrarrestado, hasta cierto punto, al avanzar a clases base de accesorios polimórficos como ::testing::Test y ::testing::Environment.Estos facilitan el desarrollador de pruebas en la encapsulación de la adquisición de los recursos de prueba en el caso de prueba o la inicialización de suite de prueba para que todo haya terminado, ya sea con éxito o con una falla diagnosticada, antes de que se ejecuten las pruebas constituyentes de cualquier caso de prueba.RAII puede mantener una división sin problemas entre fallas de configuración y fallas reales.

Sin embargo, hay una sobrecarga irreducible de manejo de archivos para la ruta de archivo de datos y Hay una sobrecarga operativa que las características de RAII del marco no hacen nada para reducir.En mis tratos con sistemas de prueba fuertes que intercambian archivos de datos, los archivos de datos solo son Más propensos a los contratiempos operativos que los archivos de origen que solo tienen que estar presentes y correctos en el tiempo de compilación.Es más probable que los archivos de datos se falten o fuera de lugar durante el tiempo de ejecución, o que contengan cosas malformadas, o de alguna manera se hayan convertido en el permiso, o de alguna manera aparecer en la revisión incorrecta.Sus usos en un sistema de prueba no son tan simples o tan rígidamente controlados como los de los archivos de origen. Cosas que no deberían pasar Poner en prueba de archivos de datos es parte de la fricción operativa de los sistemas de prueba que dependen de ellos y es proporcional a su número.

Desde archivos fuente ¿Pueden encapsular las inicializaciones de datos de prueba higiénicamente para el seguimiento de la revisión, la codificación dura puede equipararse para la extracción de un archivo, con el preprocesador haciendo la extracción como un subproducto de la compilación?En ese sentido, ¿por qué emplear otra maquinaria, con responsabilidades adicionales, para extraerlo?Puede haber buenas respuestas, como la interfaz XML sugerida con la gestión de pruebas, los sistemas de gestión de defectos, pero "son datos de prueba, así que no lo codifique duro" no es bueno.

Incluso si un conjunto de pruebas debe admitir varias configuraciones del sistema en prueba que requiere varias instancias de un elemento de datos de prueba, si el elemento de datos es convincente con construir configuraciones del conjunto de pruebas, también puede seguir codificándolo (higiénicamente) y dejar que la compilación condicional seleccione la codificación dura correcta.

Hasta ahora, no he desafiado el argumento de rastreo de revisión-hitgeina para la segregación basada en archivos de los inicializadores de datos de prueba.Acabo de expresar que los archivos de origen regulares en los que los inicializadores están codificados pueden lograr esta segregación.Y no quiero bajar ese argumento, pero quiero detenerlo a la conclusión fanática de que los inicializadores de datos de prueba deben ser en principio siempre extraídos de archivos dedicados, ya sean archivos de origen o archivos de datos.

No es necesario insistir en las razones para resistirse a esta conclusión.De esa manera se encuentra el código de prueba que es localmente menos Inteligible que el programador promedio de comidas de pizza escribiría y las organizaciones de los archivos de prueba de prueba que crecen alucinando mucho más rápido de lo necesario o saludable.Normativamente, todos los recursos principales de la suite de prueba son "algún tipo de código".El conjunto de habilidades de un programador incluye la habilidad del código de partición en archivos con granularidad apropiada para asegurar la higeina de seguimiento de revisión apropiado.No es un procedimiento mecánico, es una experiencia que debe cubrir la revisión del código.La revisión del código puede y debe asegurarse de que las inicializaciones de datos de prueba, sin embargo, se realicen, estén bien diseñadas y elaboradas con el seguimiento de revisiones de VIS al igual que en todos los demás respetos de rutina.

Línea de fondo:Si desea poder ejecutar la misma compilación de su conjunto de pruebas para una variedad de estas respuestas de red simuladas, léelo desde un archivo.Si, por otro lado, es invariante o covariante con configuraciones de compilación de la suite de prueba, por qué no ¿Código duro?

Otros consejos

(Advertencia: esta respuesta es genérica para cualquier marco de prueba unitaria)

Prefiero mantener los archivos de datos de prueba como objetos separados en un sistema de control de revisiones.Esto proporciona los siguientes beneficios:

  • podría codificar la prueba unitaria para aceptar uno o varios archivos de datos para probar una variedad de situaciones
  • puede realizar un seguimiento de los cambios en los datos según sea necesario

Si no desea que la ejecución de la prueba unitaria lea un archivo de datos, lo cual puede ser una condición necesaria en algunas situaciones, puede optar por escribir un programa o script que genere código C++ que inicialice el vector en la configuración del dispositivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top