¿Cómo garantiza un sistema complejo la calidad del código? Deja que la prueba sea lo primero

Un trasfondo empresarial

Como sistema de valores con características comerciales sólidas y años de historia acumulada, el servicio de navegación en línea de AutoNavi inevitablemente tiene una gran cantidad de códigos irrazonables, y la evolución comercial continúa presentando requisitos más altos sobre el rendimiento del sistema, los algoritmos y la arquitectura subyacente. entre los requisitos para una rápida evolución de los códigos comerciales, los algoritmos y las arquitecturas Cómo garantizar eficazmente la calidad de la rápida evolución de la refactorización se ha convertido en el principal problema de ingeniería que enfrenta el desarrollo empresarial.

2. Problemas y análisis de los métodos de garantía de calidad existentes

1 Problemas con los métodos de prueba existentes

El método convencional consiste en comparar las solicitudes de diferencias en lotes para servicios nuevos y antiguos. Este método es simple y efectivo. Es el método que hemos estado usando, pero tiene los siguientes problemas:

  • Problema de diferencia no válida: tome el motor de planificación de autobuses como ejemplo, confiando en múltiples servicios posteriores, como motor de guía a pie, búsqueda, emergencias de autobús y condiciones de la carretera, la diferencia en los resultados obtenidos conduce a muchas diferencias no válidas.
  • Mayor tiempo de ejecución: el tiempo de ejecución es mayor cuando hay más casos, al nivel de 10 minutos. Debido al alto costo de este paso, el desarrollador promedio no ejecuta diffs con demasiada frecuencia y no puede realizar pruebas de "un pequeño paso a la vez".
  • Dificultad en la resolución de problemas: cuando se encuentra una diferencia, es muy difícil solucionar el problema, porque es la diferencia de todo el nivel de solicitud y puede haber problemas en los pasos intermedios.

2 Práctica del método convencional en la industria

Empresas como ThoughtWorks y Google utilizan TDD para un desarrollo ágil y garantizan la calidad del desarrollo y la refactorización escribiendo casos de prueba unitarios, que ahora se han convertido en la mejor práctica habitual.

Introducción a la prueba de tres unidades

1 ¿Qué es una prueba unitaria?

La prueba unitaria es un trabajo de prueba que verifica la corrección de un módulo, una función o una clase.

La granularidad de la prueba es más pequeña y ligera, y el tiempo de ejecución es en segundos, lo que es especialmente adecuado para garantizar la calidad de "un pequeño paso a la vez" en la reconstrucción progresiva.

Dado que el caso de prueba unitario está dirigido a un objetivo más detallado de una función y clase, cuando un determinado caso de uso falla, el problema se puede identificar rápidamente.

2 Marco de pruebas unitarias

Los marcos de prueba de unidades comunes incluyen la serie xUnit, que tienen implementaciones correspondientes en múltiples lenguajes, como CppUnit, JUnit, NUnit ...

GTest es un marco de pruebas unitarias desarrollado por Google. Este marco tiene algunas características avanzadas, como prueba de muerte, simulacro, etc.

Elegimos el marco GTest.

3 Unit testing, refactoring, TDD y ágil

TDD (Test Driven Development) es un método de desarrollo que enfatiza las pruebas primero. La ventaja de este método es que al escribir cualquier función o modificar cualquier código, puede escribir un código de caso de prueba unitario para expresar la función de código que se implementará. Una prueba caso en sí es un Los requisitos expresados ​​por el código. Los casos de prueba acumulados pueden garantizar eficazmente la calidad del desarrollo y la posterior reconstrucción y evolución.

La refactorización y TDD son los componentes centrales de los métodos ágiles. Agile sin TDD es peligroso. Una vez que se inicia la refactorización sin protección de casos de uso, es como un caballo salvaje que se queda sin fuerza. Las pruebas unitarias y TDD son las riendas del Mustang.

Práctica de prueba de la unidad de servicio de cuatro autobuses

1 integración del marco GTest

Dirección de la biblioteca de Git: https://github.com/google/googletest

La integración del marco GTest es muy simple. Agregue la biblioteca de googletest al proyecto y agregue un enlace a libgtest:

La ejecución del caso de uso puede ser impulsada por el siguiente código:

int RCUnitTest::Excute()
{
  int argc = 2;
  char* argv[] = {const_cast<char*>(""), const_cast<char*>("--gtest_output=\"xml:./testAll.xml\"")};
  ::testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();

Control de interruptor: para evitar afectar la versión oficial, puede considerar compilar el control, o puede agregar un interruptor de elemento de configuración.

Cuando lo usamos, usamos un elemento de configuración en la entrada para controlar si se activa el caso de prueba unitaria. De forma predeterminada, solo el archivo de entrada está vinculado al compilar, y el archivo del caso de prueba unitario debe agregarse cuando se realiza la prueba unitaria. ejecutar para la operación del enlace.

2 Escritura de código de prueba

Implementando una clase derivada de la clase Test y luego usando la macro TEST_F para agregar funciones de prueba, como se muestra en el siguiente ejemplo:

class DateTimeUtilTest : public ::testing::Test
{
protected:
    virtual void SetUp()
{
    }

virtual void TearDown()
{
    }
};

TEST_F(DateTimeUtilTest, TestAddSeconds_leap)
{
    //闰年测试 2020-02-28
    tm tt;
    tt.tm_year = (2020 - 1900);
    tt.tm_mon = 1;
    tt.tm_mday = 28;
    tt.tm_hour = 23;
    tt.tm_min = 59;
    tt.tm_sec = 50;

    DateTimeUtil::AddSeconds(tt, 30);
    EXPECT_TRUE(tt.tm_sec == 20);
    EXPECT_TRUE(tt.tm_min == 0);
    EXPECT_TRUE(tt.tm_hour == 0);
    EXPECT_TRUE(tt.tm_mday == 29);
    EXPECT_TRUE(tt.tm_mon == 1);

    //非闰年测试 2019-02-28
    tm tt1;
    tt1.tm_year = (2019 - 1900);
    tt1.tm_mon = 1;
    tt1.tm_mday = 28;
    tt1.tm_hour = 23;
    tt1.tm_min = 59;
    tt1.tm_sec = 50;
    DateTimeUtil::AddSeconds(tt1, 30);
    EXPECT_TRUE(tt1.tm_sec == 20);
    EXPECT_TRUE(tt1.tm_min == 0);
    EXPECT_TRUE(tt1.tm_hour == 0);
    EXPECT_TRUE(tt1.tm_mday == 1);
    EXPECT_TRUE(tt1.tm_mon == 2);
};

En la actualidad, el motor del autobús ha acumulado 23 casos de prueba de módulos, que básicamente cubren funciones básicas como búsqueda de estaciones, búsqueda de caminos, ETA, tarifa y cortes de riesgo, y continúan acumulándose. A través de la garantía de prueba unitaria, se están llevando a cabo actividades de refactorización progresiva en cada actividad de desarrollo de versión, lo que puede garantizar efectivamente la calidad, y el número de iteraciones de prueba y el número de problemas introducidos por el nuevo código en línea siguen siendo bajos.

3 problemas y dificultades

Problema de dependencia de datos

El motor de navegación en línea es un negocio que depende en gran medida de los datos. Múltiples conjuntos de estructuras de datos están relacionados entre sí y hay muchos campos. Es difícil construir pruebas unitarias efectivas sin datos. El costo de construir datos falsos mediante un método simulado es muy alto. Y los cambios de datos harán que el caso de uso falle.

Mi practica:

Simplemente puede construir datos falsos construyendo datos falsos para obtenerlos.

Para situaciones en las que es difícil construir datos falsos, simplemente use datos reales directamente. Los cambios en los datos pueden hacer que falle esta parte de los casos de uso. No importa. Solo debe asegurarse de que los casos de uso relevantes se ajusten antes de cada reconstrucción, de modo que la calidad del proceso de reconstrucción aún pueda garantizarse. Es decir: no es necesario asegurarse de que el caso de uso se pueda pasar en cualquier momento y en cualquier lugar, sino asegurarse de que se pueda pasar antes y después de la refactorización.

4 conceptos erróneos comunes

Para los estudiantes que realmente no han practicado las pruebas unitarias y los métodos de desarrollo TDD, existen algunos malentendidos cognitivos comunes, tales como:

El tiempo de desarrollo no es suficiente, ¿cómo puedo tener tiempo para escribir pruebas unitarias?

Mi entendimiento:

  • En primer lugar, el método de desarrollo TDD enfatiza las pruebas primero, la escritura del código de prueba es primero, este proceso es equivalente al proceso de comprensión de los requisitos. ¿Eso es pensar con claridad qué función quieres lograr? Este código de prueba es el producto de aclarar los requisitos, y eso es todo, no hay más costos de tiempo.
  • El método de desarrollo TDD es una inversión típica y un beneficio continuo. Cuanto más casos de uso se acumulan, más fácil es encontrar problemas en la etapa inicial. La calidad de la refactorización está garantizada y el código se vuelve más limpio y claro. Desarrollo los estudiantes ya no tienen que lamentar el código histórico.

Con tanto código histórico, ¿cómo hacer la prueba unitaria?

Luego comience agregando el primer caso de uso. Mi enfoque es agregar casos de uso correspondientes al código involucrado en esta modificación y acumular gradualmente.

El proceso de agregar casos de uso es el proceso de comprender el código existente. Para el código histórico existente, varias intrusiones codificadas, varios acoplamientos, variables globales u objetos grandes de larga duración, la entrada real de la función se puede clasificar de manera efectiva escribiendo casos de prueba unitarios La salida también agrega una garantía efectiva para la reconstrucción.

Refactorización progresiva de código de sistema complejo de cinco valores

Para nuestros productores de código de primera línea, la mayor parte del día se trata de código, si mantiene una estructura de código razonable, fácil de leer y expandir, ¡felicitaciones! Pero en la mayoría de los casos, nos enfrentamos a varios proyectos de "acumulación" histórica de stock, que afectarán a todo el cuerpo. En este caso, se pueden hacer pequeños cambios dedicando más tiempo y cuidado, pero queremos es difícil de hacer algunas actualizaciones importantes del sistema.

Para los sistemas comerciales gigantes, la reescritura es aún más irreal en términos de control de costos y calidad. Luego, configure algunos nodos grandes, optimícelos gradualmente a través de la reconstrucción progresiva, y las variables se convierten en cambios cualitativos, que es la mejor manera de verlos de manera integral.

Las pruebas unitarias y TDD son métodos necesarios para el desarrollo efectivo de la refactorización progresiva.

Enlace original

Este artículo es el contenido original de Alibaba Cloud y no se puede reproducir sin permiso.

Supongo que te gusta

Origin blog.csdn.net/weixin_43970890/article/details/113883920
Recomendado
Clasificación