MSTest 4.4 permite ejecutar proyectos de pruebas utilizando el mismo modelo de implementación que la aplicación podría usar en producción, mediante la generación del código fuente de las pruebas y la habilitación de Native AOT y la reducción. La idea no pretende sustituir la ejecución administrada habitual de las pruebas, sino añadir un flujo nativo que revele problemas relacionados con la compilación anticipada y la eliminación del código no utilizado antes del lanzamiento de la aplicación.
Según Amaury Levé, Principal Software Engineer, usar MSTest.Sdk/4.4.0 con el destino net10.0 y establecer PublishAot=true activa la generación de código fuente de MSTest y el flujo del archivo ejecutable nativo. MSTest.Sdk utiliza Microsoft Testing Platform, o MTP, de forma predeterminada. En cambio, los proyectos que todavía usan VSTest deben revisar las directrices de migración a MTP, porque los parámetros de la línea de comandos, la integración con CI y algunas entradas de .runsettings compatibles son diferentes.
¿Qué cambia en la práctica?
Después de configurar el proyecto, las pruebas deben publicarse para los mismos sistema operativo y arquitectura a los que se dirige la aplicación. La fuente proporciona un ejemplo con el identificador linux-x64, que puede sustituirse por valores como win-x64 o osx-arm64. Tras la publicación, el archivo ejecutable resultante se ejecuta directamente, o utilizando la extensión .exe en Windows.
Este flujo reduce la dependencia de la inspección reflexiva exhaustiva del ensamblado, como la llamada a Assembly.GetTypes(), y utiliza atributos y delegados generados para crear e invocar las pruebas compatibles. Sin embargo, la generación de código fuente no significa que Reflection desaparezca; el modo predeterminado ReflectionFree conserva algunas rutas reflexivas de reserva. Al investigar problemas de compatibilidad, puede utilizarse MSTestSourceGenMode=Rooting para conservar los miembros de las pruebas detectados y mantener al mismo tiempo la ejecución reflexiva.
Un flujo de CI limitado antes de ampliarlo
La recomendación práctica es mantener la ejecución rápida de las pruebas administradas para la retroalimentación diaria y, después, seleccionar un único proyecto de pruebas directamente relacionado con el flujo de implementación y añadir una prueba de Native AOT en CI. Ambos flujos deben compararse en tres aspectos claros:
- Detectar exactamente el mismo número de pruebas.
- Obtener los mismos resultados para las pruebas.
- Registrar por separado el tiempo de publicación y ejecución nativa del tiempo de ejecución de las pruebas.
Es preferible comenzar la prueba en una tarea programada o en una fase de validación de la versión y trasladarla a cada solicitud de incorporación de cambios solo si la señal que proporciona justifica el coste adicional de publicación y ejecución. También debe elegirse un proyecto que pruebe rutas sensibles a la implementación, como la serialización, la inyección de dependencias, el enlace de configuración, las extensiones que dependen de Reflection o una biblioteca cuya compatibilidad con Native AOT el equipo necesite demostrar. En cambio, un proyecto que solo contenga pruebas computacionales sencillas no aportará mucha evidencia sobre la preparación real de la aplicación.
Limitaciones que deben convertirse en puertas de aceptación
Una parte de las pruebas puede tener éxito y el proceso finalizar correctamente aunque algunas clases no se registren. Esto ocurre, por ejemplo, cuando una clase de prueba hereda el atributo [TestClass] en lugar de declararlo directamente, o cuando la clase no es accesible, es local al archivo, estática, pública abierta o abstracta. La fuente indica que el diagnóstico MSTEST0069 ayuda a detectar uno de estos casos. Por ello, la coincidencia del número de pruebas debe ser una condición para el lanzamiento, no una observación que pueda ignorarse.
Otras limitaciones incluyen métodos de prueba públicos o métodos que utilizan parámetros ref, out o in, además de la falta de compatibilidad con algunos patrones de elementos estáticos mediante [AssemblyFixtureProvider]. Asimismo, algunas integraciones de MSTest SDK, extensiones de MTP e informes de CI no están disponibles en el flujo de Native AOT, mientras que la compatibilidad con TRX y Code Coverage sigue estando disponible según el artículo. Por ello, las advertencias del analizador y los diagnósticos de compilación deben tratarse como puertas de transición, no como advertencias que deban silenciarse.
¿Por qué es importante este enfoque?
Las pruebas administradas y el flujo de Native AOT responden a dos preguntas diferentes: el primero acelera el ciclo de desarrollo y el segundo verifica que las propias pruebas puedan funcionar dentro del modelo de implementación que utilizará la aplicación. Esto no equivale a probar exhaustivamente la pieza final de producción; la configuración, el sistema operativo, la arquitectura, los servicios externos y el empaquetado pueden ser diferentes. Sin embargo, elimina una variable importante: la diferencia entre el modelo de reducción y compilación anticipada de las pruebas y el de la aplicación.
La mejora del rendimiento no está garantizada ni debe ser el motivo principal. El tiempo de detección y de inicio puede reducirse gracias a la generación del código fuente, pero el tiempo de ejecución, el inicio del proceso, la publicación y la Reflection restante pueden dominar la duración total. La lectura editorial aquí es que el valor principal de la prueba consiste en aumentar la correspondencia entre las pruebas y la implementación, incluso si la ganancia de velocidad es limitada. El enfoque sigue siendo reversible: si el coste del flujo supera la confianza que aporta, puede reducirse su frecuencia, cambiarse el proyecto elegido o detenerse la prueba sin interrumpir el conjunto de pruebas administradas.