automated tests - test - xUnit.net-ejecuta el código una vez antes y después de TODAS las pruebas
xunit git (6)
TL; DR - Estoy buscando el equivalente de xUnit de AssemblyInitialize
de MSTest (también conocido como la característica ONE que tiene que me gusta).
Específicamente lo estoy buscando porque tengo algunas pruebas de humo de Selenium que me gustaría poder ejecutar sin otras dependencias. Tengo un accesorio que lanzará IisExpress para mí y lo matará en su eliminación. Pero haciendo esto antes de cada prueba, el tiempo de ejecución enormemente hinchado.
Me gustaría activar este código una vez al comienzo de la prueba y deshacerme de él (cerrar el proceso) al final. ¿Cómo podría hacer eso?
Incluso si puedo obtener acceso programático a algo así como "cuántas pruebas se están ejecutando actualmente", puedo descubrir algo.
¿Su herramienta de construcción proporciona esa característica?
En el mundo de Java, cuando usamos Maven como una herramienta de compilación, usamos las fases apropiadas del ciclo de vida de compilación . Por ejemplo, en su caso (pruebas de aceptación con herramientas similares al selenio), se puede hacer un buen uso de las fases de pre-integration-test
post-integration-test
para iniciar / detener una aplicación web antes / después de la integration-test
de integration-test
.
Estoy bastante seguro de que se puede configurar el mismo mecanismo en su entorno.
A partir de noviembre de 2015, xUnit 2 está disponible, por lo que existe una forma canónica de compartir funciones entre pruebas. Está documentado here .
Básicamente, necesitarás crear una clase haciendo el accesorio:
public class DatabaseFixture : IDisposable
{
public DatabaseFixture()
{
Db = new SqlConnection("MyConnectionString");
// ... initialize data in the test database ...
}
public void Dispose()
{
// ... clean up test data from the database ...
}
public SqlConnection Db { get; private set; }
}
Una clase ficticia con el atributo CollectionDefinition
. Esta clase le permite a Xunit crear una colección de prueba, y usará el accesorio dado para todas las clases de prueba de la colección.
[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
// This class has no code, and is never created. Its purpose is simply
// to be the place to apply [CollectionDefinition] and all the
// ICollectionFixture<> interfaces.
}
Luego, debe agregar el nombre de la colección a todas sus clases de prueba. Las clases de prueba pueden recibir el accesorio a través del constructor.
[Collection("Database collection")]
public class DatabaseTestClass1
{
DatabaseFixture fixture;
public DatabaseTestClass1(DatabaseFixture fixture)
{
this.fixture = fixture;
}
}
Es un poco más detallado que MsTests AssemblyInitialize
ya que debe declarar en cada clase de prueba a qué colección de prueba pertenece, pero también es más modulable (y con MsTests aún necesita poner un TestClass en sus clases)
Nota: las muestras se tomaron de la here .
Crea un campo estático e implementa un finalizador.
Puede utilizar el hecho de que xUnit crea un AppDomain para ejecutar su ensamblaje de prueba y lo descarga cuando termina. Al descargar el dominio de la aplicación, se ejecutará el finalizador.
Estoy usando este método para iniciar y detener IISExpress.
public sealed class ExampleFixture
{
public static ExampleFixture Current = new ExampleFixture();
private ExampleFixture()
{
// Run at start
}
~ExampleFixture()
{
Dispose();
}
public void Dispose()
{
GC.SuppressFinalize(this);
// Run at end
}
}
Editar: acceda al dispositivo usando ExampleFixture.Current
en sus pruebas.
No es posible hacerlo en el marco hoy. Esta es una característica planificada para 2.0.
Para hacer que esto funcione antes de 2.0, se requeriría realizar una re-arquitectura significativa en el marco, o escribir sus propios corredores que reconocieran sus propios atributos especiales.
Puede usar la interfaz IUseFixture para que esto suceda. Además, todas sus pruebas deben heredar la clase TestBase. También puede usar OneTimeFixture directamente desde su prueba.
public class TestBase : IUseFixture<OneTimeFixture<ApplicationFixture>>
{
protected ApplicationFixture Application;
public void SetFixture(OneTimeFixture<ApplicationFixture> data)
{
this.Application = data.Fixture;
}
}
public class ApplicationFixture : IDisposable
{
public ApplicationFixture()
{
// This code run only one time
}
public void Dispose()
{
// Here is run only one time too
}
}
public class OneTimeFixture<TFixture> where TFixture : new()
{
// This value does not share between each generic type
private static readonly TFixture sharedFixture;
static OneTimeFixture()
{
// Constructor will call one time for each generic type
sharedFixture = new TFixture();
var disposable = sharedFixture as IDisposable;
if (disposable != null)
{
AppDomain.CurrentDomain.DomainUnload += (sender, args) => disposable.Dispose();
}
}
public OneTimeFixture()
{
this.Fixture = sharedFixture;
}
public TFixture Fixture { get; private set; }
}
EDITAR: soluciona el problema que el nuevo dispositivo crea para cada clase de prueba.
Yo uso AssemblyFixture ( NuGet ).
Lo que hace es proporcionar una IAssemblyFixture<T>
que está reemplazando cualquier IClassFixture<T>
donde desea que la vida del objeto sea como el ensamblaje de prueba.
Ejemplo:
public class Singleton { }
public class TestClass1 : IAssemblyFixture<Singleton>
{
readonly Singletone _Singletone;
public TestClass1(Singleton singleton)
{
_Singleton = singleton;
}
[Fact]
public void Test1()
{
//use singleton
}
}
public class TestClass2 : IAssemblyFixture<Singleton>
{
readonly Singletone _Singletone;
public TestClass2(Singleton singleton)
{
//same singleton instance of TestClass1
_Singleton = singleton;
}
[Fact]
public void Test2()
{
//use singleton
}
}