Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Sugerencia
Este contenido es un extracto del libro electrónico "Patrones de aplicaciones empresariales con .NET MAUI", disponible en Documentación de .NET o como un PDF descargable y gratuito que se puede leer sin conexión.
Las aplicaciones multiplataforma experimentan problemas similares a las aplicaciones de escritorio y aplicaciones web. Los usuarios móviles variarán en función de sus dispositivos, conectividad de red, disponibilidad de servicios y otros diversos factores. Por lo tanto, las aplicaciones multiplataforma se deben probar tal y como se usarían en el mundo real para mejorar su calidad, confiabilidad y rendimiento. Se deben realizar muchos tipos de pruebas en una aplicación, incluidas las pruebas unitarias, las pruebas de integración y las pruebas de interfaz de usuario. Las pruebas unitarias son la forma más común y esencial para crear aplicaciones de alta calidad.
Una prueba unitaria toma una pequeña unidad de la aplicación, normalmente un método, lo aísla del resto del código y comprueba que se comporta según lo previsto. Su objetivo es comprobar que cada unidad funcional funciona como se espera, para que los errores no se propaguen por toda la aplicación. Detectar un error allí donde se produce es más eficaz que observar el efecto de un error indirectamente en un punto secundario de error.
Las pruebas unitarias tienen un mayor efecto en la calidad del código cuando son parte integral del flujo de trabajo de desarrollo de software. Las pruebas unitarias pueden actuar como documentación de diseño y especificaciones funcionales para una aplicación. En cuanto se haya escrito un método, se deben escribir pruebas unitarias que comprueben el comportamiento del método en respuesta a casos de datos de entrada estándar, límites e incorrectos, y que comprueben las suposiciones explícitas o implícitas realizadas por el código. Como alternativa, con el desarrollo controlado por pruebas, las pruebas unitarias se escriben antes que el código. Para obtener más información sobre el desarrollo controlado por pruebas y cómo implementarlo, consulte Tutorial: Desarrollo controlado por pruebas mediante el Explorador de pruebas..
Nota
Las pruebas unitarias son muy eficaces frente a la regresión. Es decir, una funcionalidad que solía funcionar, pero que ha sido perturbada por una actualización incorrecta.
Las pruebas unitarias suelen usar el patrón arrange-act-assert:
| Paso | Descripción |
|---|---|
| Organizar | Inicializa los objetos y establece el valor de los datos que se pasan al método objeto de las pruebas. |
| Actuar | Invoca al método objeto de las pruebas con los argumentos necesarios. |
| Assert | Comprueba si la acción del método objeto de las pruebas se comporta de la forma prevista. |
Este patrón garantiza que las pruebas unitarias sean legibles, autodescriptivas y coherentes.
Elija un marco de pruebas y una plataforma
Un marco de pruebas define los atributos, las aserciones y el ciclo de vida de prueba que se usan para escribir pruebas. Una plataforma de prueba detecta y ejecuta esas pruebas y se integra con el IDE, la línea de comandos y la canalización de integración continua (CI). VSTest y Microsoft.Testing.Platform (MTP) son plataformas de prueba, no reemplazos de marcos como MSTest.
Los marcos siguientes admiten pruebas para la lógica de aplicación .NET MAUI independiente de la plataforma:
| Framework | Documentación del framework | Configuración de MTP |
|---|---|---|
| MSTest | Introducción a MSTest y Primeros pasos con MSTest. | Ejecute pruebas con MSTest y EL SDK de MSTest. |
| NUnit | Primeros pasos con C# y NUnit. | Ejecutor de NUnit. |
| xUnit.net | Primeros pasos con C# y xUnit.net. | xUnit.net v3 tiene compatibilidad integrada con MTP. xUnit.net v2 requiere una integración de terceros que no es admitida por xUnit.net ni Microsoft. |
| TUnit | Documentación de TUnit. | TUnit se basa en MTP y no admite VSTest. |
MTP ejecuta pruebas como aplicaciones ejecutables. Para la configuración de LA CLI, IDE y CI, consulte Ejecutar y depurar pruebas de MTP. Con el SDK de .NET 10 o posterior, puede seleccionar el modo MTP de dotnet test en global.json. Este modo requiere MTP 1.7 o una versión posterior, y todos los proyectos de prueba seleccionados deben ser compatibles con MTP. No mezcle proyectos basados en VSTest y proyectos basados en MTP en una misma ejecución de pruebas. Las plataformas también usan diferentes opciones de línea de comandos. Para obtener más información, consulte Pruebas con dotnet test.
Comprender los límites de las pruebas de .NET MAUI
Para ejecutar pruebas unitarias en la máquina de desarrollo, aísle la lógica de negocios, la validación y los modelos de visualización de dependencias específicas de la plataforma. Un enfoque consiste en colocar ese código en una biblioteca de clases de .NET a la que hagan referencia tanto la aplicación como el proyecto de prueba. Como alternativa, configure la aplicación o biblioteca de clases de .NET MAUI para que exponga un marco de destino compatible que no sea específico de ninguna plataforma, como net10.0. En el caso de un proyecto de aplicación, ese marco de destino debe generar una biblioteca en lugar de un archivo ejecutable. Mantener el código nativo de arranque y las implementaciones específicas de la plataforma al margen de ese destino. Para obtener información sobre la configuración del proyecto, consulte Pruebas unitarias de .NETMAUI.
Un proyecto de prueba que no es específico de ninguna plataforma no crea un contexto de aplicación nativo de .NET MAUI. Reemplace las dependencias de navegación, el despacho de la interfaz de usuario y los servicios del dispositivo por dobles de prueba cuando pruebe la lógica de la aplicación. Estas pruebas no comprueban la representación nativa, los permisos de dispositivo ni las implementaciones reales de los servicios que reemplazas.
Para probar código que requiere API específicas de la plataforma o controladores de controles nativos, utilice un host de pruebas compatible con la plataforma o un ejecutor de pruebas en dispositivos. MTP se puede hospedar en una aplicación de plataforma, pero seleccionar MTP para un proyecto de prueba para escritorio no lo convierte en una aplicación de prueba para dispositivos. Para obtener información sobre los ejecutores de pruebas en dispositivos y las opciones de pruebas específicas de cada plataforma, incluidos sus requisitos de versión, consulte Pruebas unitarias de .NETMAUI. Para automatizar las interacciones con la aplicación implementada, consulte Pruebas de iu con Appium. Ejecute esas pruebas en las plataformas admitidas.
Inserción de dependencias y pruebas unitarias
Para aislar el código sometido a prueba, use la inyección por constructor para proporcionar dobles de prueba para sus dependencias. Los dobles de prueba, como los objetos ficticios y simulados (fakes y mocks), implementan las mismas interfaces que los servicios reales, pero proporcionan un comportamiento controlado para las pruebas. Para obtener instrucciones de arquitectura, consulte inyección de dependencias.
Por ejemplo, la OrderDetailViewModel de la aplicación eShop recibe IAppEnvironmentService, INavigationService y ISettingsService dependencias a través de su constructor. Proporcione implementaciones de prueba para las dependencias que se utilizan durante la prueba, en lugar de llamar a servicios web reales o API de dispositivos.
Las pruebas del modelo de vista de catálogo de eShop muestran una configuración completa: crean una instancia de AppEnvironmentService con servicios simulados, seleccionan dichos servicios y la pasan al modelo de vista junto con un servicio de navegación simulado. Consulte las pruebas de ejemplo que se mantienen actualizadas para obtener el código completo del constructor y de inicialización. La sustitución de las dependencias de los servicios permite aislar la lógica de la aplicación, pero no elimina los requisitos nativos del resto del código al que llama la prueba.
Prueba de aplicaciones MVVM
Cuando los modelos y los modelos de vista no requieren un contexto de aplicación nativo, pruébelos con los mismos marcos y técnicas que se usan para otras clases de .NET. Algunos patrones habituales de las clases de modelo y modelo de vista se benefician de técnicas específicas de pruebas unitarias.
Sugerencia
Pruebe un comportamiento con cada prueba unitaria. Para mantener las pruebas repetibles, aisladas y fáciles de diagnosticar, limite cada prueba a un único aspecto. Para obtener más orientación, consulte Prácticas recomendadas para las pruebas unitarias con .NET.
No se sienta tentado a hacer que una prueba unitaria ejercite más de un aspecto del comportamiento de la unidad. Si lo hace, las pruebas son difíciles de leer y actualizar. También puede provocar confusión al interpretar un fallo.
La aplicación multiplataforma eShop usa MSTest. En MSTest, aplique TestClass a la clase de prueba y TestMethod a cada método de prueba. Para ver los atributos, las firmas y la guía del ciclo de vida, consulte Escribir pruebas con MSTest.
Para ejecutar la misma prueba con entradas diferentes, combine TestMethod con DataRow para los datos insertados o DynamicData para los datos proporcionados por un miembro. Estos atributos proporcionan casos de prueba; no son marcos de pruebas independientes ni alternativas a TestMethod. El atributo heredado DataSource solo está disponible para .NET Framework, no para proyectos de .NET ni .NET MAUI modernos. Para ver las opciones admitidas, consulte Pruebas controladas por datos en MSTest.
Prueba de la funcionalidad asincrónica
Los modelos de vista suelen invocar operaciones de servicio asincrónicas. Para probar el resultado en lugar de un estado intermedio, espere a que finalice la operación antes de hacer una aserción. Escriba métodos de MSTest asincrónicos que devuelvan Tasko ValueTask con MSTest 3.3 o posterior. No use métodos de prueba async void. Para ver las signaturas compatibles, consulte Escribir pruebas con MSTest.
Por ejemplo, ProductsPropertyIsNotNullAfterViewModelInitializationTest en las pruebas del modelo de vista de catálogo de eShop crea un modelo de vista con servicios simulados, espera a que finalice InitializeAsync y comprueba que Products no es nulo. La prueba comprueba la inicialización con datos controlados, no el comportamiento del servicio web de catálogo real. Para el flujo de inicialización y navegación de la aplicación, consulte Navegación.
Para los comandos asincrónicos, espere a que finalice la ejecución mediante la API asincrónica del comando antes de comprobar el resultado. Llamar ICommand.Execute solo no garantiza que se haya completado el trabajo asincrónico. Para obtener información sobre las API de comandos de MVVM Toolkit, consulte AsyncRelayCommand.
Prueba de implementaciones de INotifyPropertyChanged
La interfaz INotifyPropertyChanged permite que las vistas reaccionen a los cambios en los modelos y los modelos de vista. Para probar una notificación, asocie un controlador de eventos a PropertyChanged, cambie la propiedad y compruebe que el controlador recibe el valor esperado de PropertyName. No trate una notificación sobre una propiedad no relacionada como un éxito.
La prueba SettingForenamePropertyShouldRaisePropertyChanged de las pruebas del modelo de vista de validación de eShop demuestra este patrón. Se suscribe al evento PropertyChanged del objeto Forename, establece Forename.Value y comprueba si hay una notificación para Value.
Esta prueba comprueba el contrato de notificación. No comprueba que un enlace de XAML o un control nativo se actualicen correctamente; cubre esos comportamientos con pruebas de IU.
Prueba de la comunicación basada en mensajes
Para la comunicación basada en mensajes, use IMessenger de MVVM Toolkit, como WeakReferenceMessenger. Para obtener información sobre el contrato de mensajería y ejemplos de API, consulte Comunicación entre componentes con acoplamiento flexible y Messenger de MVVM Toolkit.
Para probar un publicador, registre un destinatario para el tipo de mensaje esperado, ejecute la operación y compruebe que el destinatario recibe la carga útil esperada. Para probar un destinatario, envíe un mensaje conocido y compruebe el estado del modelo de vista resultante. Espere a que se completen los comandos asincrónicos antes de hacer una aserción.
Para aislar las pruebas de mensajería, cree una instancia de Messenger para cada prueba e inserte esa misma instancia en el código que se va a probar. Si el código usa WeakReferenceMessenger.Default, anule el registro de los destinatarios de la prueba durante la limpieza y evite que las pruebas simultáneas interfieran con el estado de mensajero compartido. Las referencias débiles no garantizan que el recolector de elementos no utilizados libere al destinatario antes de la siguiente prueba. Para ver las opciones de limpieza y de aislamiento, consulte ciclo de vida de las pruebas de MSTest y Controlar la ejecución de pruebas.
Nota
MessagingCenter está en desuso en .NET 10. Para código nuevo, utilice MVVM Toolkit Messenger en su lugar.
Prueba del control de excepciones
Para comprobar que las acciones o entradas no válidas producen una excepción, use las aserciones de excepción del marco. En MSTest 3.8 o posterior, Assert.Throws<T> acepta el tipo de excepción especificado o un tipo derivado, mientras Assert.ThrowsExactly<T> que requiere el tipo exacto. Para el código asincrónico, espere a que finalice Assert.ThrowsAsync<T> o Assert.ThrowsExactlyAsync<T> en lugar de pasar una operación asincrónica a una aserción sincrónica. Para obtener ejemplos y API específicas de la versión, consulte Aserciones de MSTest.
Una aserción de excepción pasa cuando observa la excepción esperada; la excepción no es un error de prueba no controlado. Si la operación en pruebas construye vistas nativas o usa handlers de plataforma, todavía necesita el contexto de aplicación adecuado. Una comprobación de excepción no proporciona ese contexto.
Sugerencia
Evite escribir pruebas unitarias que examinen las cadenas de los mensajes de excepción. Las cadenas de los mensajes de excepción pueden cambiar con el tiempo, por lo que las pruebas unitarias que dependen de su presencia se consideran frágiles.
Prueba de validación
Pruebe las reglas de validación y el estado expuesto por ValidatableObject<T>. Para cada regla, cubra las entradas válidas, no válidas y los casos límite. Para ver el modelo de validación usado por la aplicación, consulte Validación.
Las pruebas del modelo de vista de validación de eShop proporcionan un servicio de navegación ficticio a MockViewModel y ejercen su Validate método.
CheckValidationPassesWhenBothPropertiesHaveDataTest comprueba que la validación se realiza correctamente cuando ambos nombres tienen datos.
CheckValidationFailsWhenOnlyForenameHasDataTest comprueba que la falta de un apellido hace que falle la validación.
Compruebe las Valuepropiedades , IsValidy Errors , así como el resultado general. Por ejemplo, cuando solo el nombre del usuario tiene datos, el nombre del usuario debe permanecer válido sin errores, mientras que el apellido debe ser no válido y presentar errores. Estas aserciones comprueban el modelo de validación, no si la interfaz de usuario muestra los errores correctamente.
Resumen
Una prueba unitaria toma una pequeña unidad de la aplicación, normalmente un método, lo aísla del resto del código y comprueba que se comporta según lo previsto. Su objetivo es comprobar que cada unidad funcional funciona como se espera, para que los errores no se propaguen por toda la aplicación.
Para aislar la lógica de la aplicación, reemplace las dependencias de los servicios por dobles de prueba. Elija un marco de pruebas y una plataforma de pruebas compatibles, y use sus atributos y aserciones admitidos.
Pruebe modelos independientes de la plataforma y modelos de vista con pruebas unitarias de .NET convencionales. Utiliza pruebas de dispositivo, de plataforma, de integración y de interfaz de usuario para comportamientos que dependen de un servicio real o del contexto nativo de la aplicación.