Startup
El StartupAttribute
es un atributo personalizado diseñado para facilitar la creación de pruebas unitarias que validen el proceso de inicialización de servicios de inicio (startup services) en tu aplicación. Este atributo automatiza la creación de instancias de servicios de inicio y la ejecución de su método de inicialización, lo que permite probar si la configuración de servicios se realiza correctamente y sin errores.
¿Cómo Funciona?
El StartupAttribute
funciona como un proveedor de datos para las pruebas unitarias utilizando xUnit. Cuando se aplica a un método de prueba, este atributo realiza las siguientes acciones:
- Escanear el ensamblado: Identifica todas las clases que implementan la interfaz
IStartup
, que es un marcador típico para servicios de inicialización. - Crear instancias: Para cada servicio de inicio encontrado, se crea una instancia utilizando su constructor predeterminado.
- Ejecutar la inicialización: Se ejecuta el método
Initialize
del servicio de inicio, simulando el proceso de configuración de servicios. - Proveer datos: Suministra la instancia del servicio de inicio y cualquier excepción que se produzca durante su inicialización a la prueba unitaria.
Métodos
GetData
GetData(MethodInfo testMethod)
Este método es el núcleo del StartupAttribute
. Se encarga de realizar las siguientes acciones:
- Localizar Servicios de Inicio: Busca en el ensamblado especificado por el parámetro genérico
TAssemblyScan
todas las clases que cumplen con las siguientes condiciones:- Implementan la interfaz
IStartup
. - No son una interfaz o clase abstracta.
- Implementan la interfaz
- Crear Instancias y Ejecutar Inicialización: Para cada servicio de inicio encontrado:
- Crea una instancia del servicio de inicio utilizando
Activator.CreateInstance
. - Crea una instancia de
ServiceCollection
yConfigurationBuilder
para simular el entorno de inicialización. - Ejecuta el método
Initialize
del servicio de inicio, capturando cualquier excepción que se produzca durante la inicialización.
- Crea una instancia del servicio de inicio utilizando
- Retornar Datos: Retorna una secuencia de arrays de objetos, cada array contiene:
- La instancia del servicio de inicio (
IStartup
). - La excepción que se produjo durante la inicialización (o
null
si no hubo excepción).
- La instancia del servicio de inicio (
Implementación
El StartupAttribute
se implementa como un atributo personalizado que hereda de DataAttribute
de xUnit. Recibe un parámetro genérico TAssemblyScan
que indica el ensamblado en el que buscar los servicios de inicio.
namespace CodeDesignPlus.Net.xUnit.Microservice.Attributes;
/// <summary>/// A custom attribute for providing data to test methods that validate startup services./// </summary>/// <typeparam name="TAssemblyScan">The type of the assembly to scan for startup services.</typeparam>[AttributeUsage(AttributeTargets.Method)]public class StartupAttribute<TAssemblyScan> : DataAttribute{ /// <summary> /// Gets the data for the test method. /// </summary> /// <param name="testMethod">The test method for which data is being provided.</param> /// <returns>An enumerable of object arrays representing the data for the test method.</returns> public override IEnumerable<object[]> GetData(MethodInfo testMethod) { var services = new ServiceCollection(); var configuration = new ConfigurationBuilder().Build();
var startups = typeof(TAssemblyScan).Assembly .GetTypes() .Where(x => !x.FullName.StartsWith("Castle") || !x.FullName.Contains("DynamicProxyGenAssembly")) .Where(x => typeof(IStartup).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .Select(x => (IStartup)Activator.CreateInstance(x)) .ToList();
foreach (var startup in startups) { var exception = Record.Exception(() => startup.Initialize(services, configuration));
yield return new object[] { startup, exception }; } }}
Ejemplo de Uso
El siguiente ejemplo muestra cómo utilizar el StartupAttribute
en un método de prueba unitaria:
namespace CodeDesignPlus.Net.xUnit.Microservice.Test.Validations;
/// <summary>/// A class for validating startup services./// </summary>public class StartupTest{ /// <summary> /// Validates that the startup services do not throw exceptions during initialization. /// </summary> [Theory] [Startup<Startup>] public void Sturtup_CheckNotThrowException(IStartup startup, Exception exception) { // Assert Assert.NotNull(startup); Assert.Null(exception); }}
En este ejemplo:
[Startup<Startup>]
crea instancias de todos los servicios de inicio en el ensamblado donde se defineStartup
que implementanIStartup
.- El método de prueba recibe la instancia del servicio de inicio y cualquier excepción que se haya producido durante su inicialización.
- La prueba verifica que la inicialización del servicio de inicio se realice sin excepciones.
Conclusiones
El StartupAttribute
simplifica la validación del proceso de inicialización de servicios de inicio en pruebas unitarias. Al automatizar la creación de instancias y la ejecución del método de inicialización, este atributo permite a los desarrolladores asegurar que sus servicios se configuran correctamente y están listos para su uso en la aplicación.