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.
Tipos de correcciones de compatibilidad es una de dos tecnologías que el marco de Microsoft Fakes utilice para permitir fácilmente aislar componentes en pruebas del entorno.Las cuñas desvían llamadas a métodos específicos al código que escribe como parte de la prueba.Muchos métodos devuelven varios resultados dependientes en condiciones externas, pero un correcciones de compatibilidad está bajo el control de pruebas y puede devolver resultados coherentes en cada llamada.Esto hace las pruebas más fáciles escribir.
Utilice las cuñas para aislar el código de los ensamblados que no forman parte de la solución.Para aislar los componentes de la solución de uno en uno, recomendamos utilizar códigos auxiliares.
Para una guía de información general y del tutorial, vea Aislar el código probado con Microsoft Fakes
Requisitos
- Visual Studio Ultimate
Vea Vídeo (1h16): Código O.N.U-comprobable de prueba con Fakes en Visual Studio 2012
En este tema
Esto es lo que se cubrirá en este tema:
Ejemplo: El error del año 2000
Agregar ensamblados de las falsificaciones
Utilice ShimsContext
Escriba las pruebas con Shims
Cuñas para los diferentes tipos de métodos
Cambiar el comportamiento predeterminado
Llamar al método original del método de calce
Ejemplo: El error del año 2000
Veamos un método que produce una excepción el 1 de enero de 2000:
// code under test
public static class Y2KChecker {
public static void Check() {
if (DateTime.Now == new DateTime(2000, 1, 1))
throw new ApplicationException("y2kbug!");
}
}
Probar este método es especialmente problemático porque el programa depende de DateTime.Now, un método que depende del reloj del equipo, un método no determinista y dependiente del ambiente.Además, DateTime.Now es una propiedad estática por lo que no se puede utilizar aquí un tipo de código auxiliar.Este problema es sintomático del problema de aislamiento en las pruebas unitarias: programas que llaman directamente a la API de las bases de datos, se comunican con los servicios web, etc., son complejos para las pruebas unitarias porque su lógica depende del entorno.
Aquí es donde se deben utilizar las cuñas.Los tipos de cuñas proporcionan un mecanismo para desviar cualquier método .NET a un delegado definido por el usuario.Los tipos de cuñas son codificados por el generador de emulaciones y utilizan los delegados, que denominamos tipos de correcciones de compatibilidad, para especificar las nuevas implementaciones del método.
La prueba siguiente muestra cómo utilizar el tipo de cuña, ShimDateTime, para proporcionar una implementación personalizada de DateTime.Now:
//unit test code
// create a ShimsContext cleans up shims
using (ShimsContext.Create()
// hook delegate to the shim method to redirect DateTime.Now
// to return January 1st of 2000
ShimDateTime.NowGet = () => new DateTime(2000, 1, 1);
Y2KChecker.Check();
}
Cómo utilizar Shims
Agregar ensamblados de las falsificaciones
En el explorador de soluciones, expanda References el proyecto de prueba unitaria.
- Si está trabajando en Visual Basic, debe seleccionar mostrar todos los archivos de la barra de herramientas del explorador de soluciones, para ver la lista de referencias.
Seleccione el ensamblado que contiene las definiciones de clases de las que desea crear las cuñas.Por ejemplo, si desea calzar DateTime, seleccione System.dll
En el menú contextual, elija Agregue el ensamblado de las falsificaciones.
Utilice ShimsContext
Al utilizar tipos de cuñas en un marco de pruebas unitarias, debe ajustar el código en un ShimsContext para controlar la duración de sus cuñas.Si no requiriéramos esto, las cuñas durarían hasta que el AppDomain se cerrara.La manera más fácil de crear un ShimsContext es mediante el método estático Create() tal y como se muestra en el siguiente código:
//unit test code
[Test]
public void Y2kCheckerTest() {
using(ShimsContext.Create()) {
...
} // clear all shims
}
Es fundamental desechar correctamente cada contexto de la cuña.En general, llame siempre al ShimsContext.Create dentro de una declaración using para garantizar el borrado adecuado de las cuñas registradas.Por ejemplo, podría registrar una cuña para un método de prueba que reemplaza al método DateTime.Now con un delegado que devuelve siempre el primero de enero de 2000.Si olvida borrar la cuña registrada en el método de prueba, el resto de la ejecución de pruebas devolvería siempre el primero de enero de 2000 como el valor de DateTime.Now.Esto podría ser sorprendente y confuso.
Escriba una prueba con las cuñas
En el código de prueba, inserte un desvío para el método que desee imitar.Por ejemplo:
[TestClass]
public class TestClass1
{
[TestMethod]
public void TestCurrentYear()
{
int fixedYear = 2000;
using (ShimsContext.Create())
{
// Arrange:
// Detour DateTime.Now to return a fixed date:
System.Fakes.ShimDateTime.NowGet =
() =>
{ return new DateTime(fixedYear, 1, 1); };
// Instantiate the component under test:
var componentUnderTest = new MyComponent();
// Act:
int year = componentUnderTest.GetTheCurrentYear();
// Assert:
// This will always be true if the component is working:
Assert.AreEqual(fixedYear, year);
}
}
}
<TestClass()> _
Public Class TestClass1
<TestMethod()> _
Public Sub TestCurrentYear()
Using s = Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create()
Dim fixedYear As Integer = 2000
' Arrange:
' Detour DateTime.Now to return a fixed date:
System.Fakes.ShimDateTime.NowGet = _
Function() As DateTime
Return New DateTime(fixedYear, 1, 1)
End Function
' Instantiate the component under test:
Dim componentUnderTest = New MyComponent()
' Act:
Dim year As Integer = componentUnderTest.GetTheCurrentYear
' Assert:
' This will always be true if the component is working:
Assert.AreEqual(fixedYear, year)
End Using
End Sub
End Class
Los nombres de clase de correcciones de compatibilidad son compuestos anteponiendo Fakes.Shim al nombre de tipo original.
Las cuñas funcionan incrustando desvíos en el código de la aplicación en pruebas.Una llamada al método original se produce siempre que, el sistema de Fakes realiza un desvío, en lugar de la llamada al método real, el código del código.
Observe que desvíos se crean y eliminar en tiempo de ejecución.Debe crear un desvío dentro de la vida de ShimsContext.Cuando se elimina, cualquier cuñas crearla mientras estaba activo se quita.La mejor manera de hacer esto está dentro de una instrucción de using.
Puede aparecer un error de compilación que decía que no existe el espacio de nombres Fakes.Este error aparece a veces cuando hay otros errores de compilación.Corrija otros errores y desaparecerá.
Cuñas para los diferentes tipos de métodos
Los tipos de correcciones de compatibilidad permiten reemplace cualquier método.NET, incluidos los métodos estáticos o métodos no virtuales, con los propios delegados.
Métodos estáticos
Las propiedades para asociar las cuñas a los métodos estáticos se colocan en un tipo de corrección de compatibilidad.Cada propiedad tiene sólo un establecedor que puede utilizar para asociar un delegado al método de destino.Por ejemplo, dada una clase MyClass con un método estático MyMethod:
//code under test
public static class MyClass {
public static int MyMethod() {
...
}
}
Podemos adjuntar una cuña a MyMethod que siempre devuelve 5:
// unit test code
ShimMyClass.MyMethod = () =>5;
Métodos de instancia (para todas las instancias)
De forma similar a los métodos estáticos, los métodos de instancia se pueden ser calzados para todas las instancias.Las propiedades para asociar dichas cuñas se colocan en un tipo anidado denominado AllInstances para evitar confusiones.Por ejemplo, dada una clase MyClass con un método de la instancia MyMethod:
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Puede adjuntar un correcciones de compatibilidad a MyMethod que siempre devuelve 5, independientemente de la instancia:
// unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;
La estructura de tipos generada de ShimMyClass se parece al código siguiente:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public static class AllInstances {
public static Func<MyClass, int>MyMethod {
set {
...
}
}
}
}
Observe que el simulador pasa la instancia del runtime como primer argumento del delegado en este caso.
Métodos de instancia (para una instancia del runtime)
Los métodos de instancia también se pueden calzar por varios delegados, según el receptor de la llamada.Esto permite al mismo método de instancia tener distintos comportamientos por instancia del tipo.Las propiedades para configurar esas cuñas son a su vez métodos instanciados del mismo tipo de corrección de compatibilidad.Cada tipo de cuña instanciada también esta asociada a una instancia sin formato de un tipo con cuña.
Por ejemplo, dada una clase MyClass con un método de la instancia MyMethod:
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Podemos configurar dos tipos de cuñas de MyMethod tales que el primero siempre devuelve 5 y el segundo siempre devuelve 10:
// unit test code
var myClass1 = new ShimMyClass()
{
MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };
La estructura de tipos generada de ShimMyClass se parece al código siguiente:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public Func<int> MyMethod {
set {
...
}
}
public MyClass Instance {
get {
...
}
}
}
Se puede obtener acceso a la instancia real de tipo con cuña mediante la propiedad de instancia:
// unit test code
var shim = new ShimMyClass();
var instance = shim.Instance;
El tipo de cuña también tiene una conversión implícita al tipo con cuña, por lo que puede usar normalmente simplemente el tipo de cuña tal como es:
// unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // implicit cast retrieves the runtime
// instance
Constructores
Los constructores también pueden ser calzados para asociar tipos de calce a los objetos futuros.Cada constructor esta expuesto como un método estático Constructor en el tipo de cuña.Por ejemplo, dada una clase MyClass con un constructor que toma un entero:
// code under test
public class MyClass {
public MyClass(int value) {
this.Value = value;
}
...
}
Configuramos el tipo de calce del constructor para que cada instancia futura devuelva -5 cuando se invoca al captador de valor, independientemente del valor en el constructor:
// unit test code
ShimMyClass.ConstructorInt32 = (@this, value) => {
var shim = new ShimMyClass(@this) {
ValueGet = () => -5
};
};
Observe que cada tipo de correcciones de compatibilidad expone dos constructores.El constructor predeterminado se debe usar cuando una nueva instancia es necesaria, mientras que el constructor que toma una instancia calzada como argumento se utiliza solo en cuñas de constructor :
// unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }
La estructura generada del tipo de ShimMyClass se parece al siguiente código:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass>
{
public static Action<MyClass, int> ConstructorInt32 {
set {
...
}
}
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }
...
}
Miembros base
Se puede obtener acceso a las propiedades de calce de los miembros base creando una cuña para el tipo base y pasando la instancia secundaria como un parámetro al constructor de la clase base del calce.
Por ejemplo, dada una clase MyBase con un método de instancia MyMethod y un subtipo MyChild:
public abstract class MyBase {
public int MyMethod() {
...
}
}
public class MyChild : MyBase {
}
Podemos configurar una cuña de MyBase creando un nuevo calce de ShimMyBase:
// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };
Observe que el tipo secundario de calce se convierte implícitamente en la instancia secundaria cuando se pasa como un parámetro al constructor base del calce.
La estructura de tipo generada de ShimMyChild y de ShimMyBase es similar al código siguiente:
// Fakes generated code
public class ShimMyChild : ShimBase<MyChild> {
public ShimMyChild() { }
public ShimMyChild(Child child)
: base(child) { }
}
public class ShimMyBase : ShimBase<MyBase> {
public ShimMyBase(Base target) { }
public Func<int> MyMethod
{ set { ... } }
}
Constructores estáticos
Los tipos de calce exponen un método estático StaticConstructor para calzar el constructor estático de un tipo.Puesto que los constructores estáticos se ejecutan sólo una vez, deberá asegurarse de que el calce está configurado antes de que se obtenga acceso a cualquier miembro de ese tipo.
Finalizadores
Los finalizadores no se admiten en emulación.
Métodos privados
El generador de código de emulación creará las propiedades de calce para los métodos privados que tienen sólo tipos visibles en la firma, los tipos de parámetro i.e. y el tipo de valor devuelto visible.
Enlazar interfaces
Cuando un tipo calzado implementa una interfaz, el generador de código emite un método que permite enlazar a todos los miembros de esa interfaz inmediatamente.
Por ejemplo, dada una clase MyClass que implementa IEnumerable<int>:
public class MyClass : IEnumerable<int> {
public IEnumerator<int> GetEnumerator() {
...
}
...
}
Podemos calzar las implementaciones de IEnumerable<int> en MyClass llamando al método bind:
// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });
La estructura de tipo generada de ShimMyClass se parece al siguiente código:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public ShimMyClass Bind(IEnumerable<int> target) {
...
}
}
Cambiar el comportamiento predeterminado
Cada tipo de calce generado contiene una instancia de la interfaz IShimBehavior mediante la propiedad ShimBase<T>.InstanceBehavior.Se utiliza el comportamiento cuando un cliente llama a un miembro de instancia que no se ha calzado explícitamente.
Si el comportamiento no se ha establecido explícitamente, utiliza la instancia devuelta por la propiedad estática ShimsBehaviors.Current.De forma predeterminada, esta propiedad devuelve un comportamiento que produce una excepción de NotImplementedException.
El comportamiento se puede cambiar en cualquier momento estableciendo la propiedad InstanceBehavior en cualquier instancia de calce.Por ejemplo, el siguiente fragmento de código cambia la cuña a un comportamiento que no hace nada ni devuelve el valor predeterminado de retorno tipo- que es, valor predeterminado (T):
// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;
El comportamiento también se puede cambiar globalmente para todas las instancias calzadas para las que la propiedad InstanceBehavior no se estableció la propiedad explícitamente fijando la propiedad estática de ShimsBehaviors.Current:
// unit test code
// change default shim for all shim instances
// where the behavior has not been set
ShimsBehaviors.Current =
ShimsBehaviors.DefaultValue;
Detectar accesos al entorno
Es posible asociar un comportamiento a todos los miembros, incluidos los métodos estáticos, de un tipo determinado asignando el comportamiento ShimsBehaviors.NotImplemented a la propiedad estática Behavior del tipo de calce correspondiente:
// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();
Simultaneidad
Los tipos de calce se aplican a todos los subprocesos de AppDomain y no tienen afinidad con subprocesos.Esto es un hecho importante si piensa utilizar un ejecutor de pruebas que soporta pruebas de concurrencia: las pruebas que implican tipos de calce no se pueden ejecutar simultáneamente.Esta propiedad no la cumple el runtime de emulación.
Llamar al método original del método de calce
Imagine que deseamos escribir realmente el texto para el sistema de archivos después de validar el nombre de archivo pasado al método.En ese caso, desearíamos llamar al método original en medio del método de calce.
El primer enfoque para solucionar este problema es incluir una llamada al método original utilizando un delegado y ShimsContext.ExecuteWithoutShims() como en el código siguiente:
// unit test code
ShimFile.WriteAllTextStringString = (fileName, content) => {
ShimsContext.ExecuteWithoutShims(() => {
Console.WriteLine("enter");
File.WriteAllText(fileName, content);
Console.WriteLine("leave");
});
};
Otro enfoque es establecer la cuña en null, llamar al método original y restaurar el calce.
// unit test code
ShimsDelegates.Action<string, string> shim = null;
shim = (fileName, content) => {
try {
Console.WriteLine("enter”);
// remove shim in order to call original method
ShimFile.WriteAllTextStringString = null;
File.WriteAllText(fileName, content);
}
finally
{
// restore shim
ShimFile.WriteAllTextStringString = shim;
Console.WriteLine("leave");
}
};
// initialize the shim
ShimFile.WriteAllTextStringString = shim;
Limitaciones
Las cuñas no se pueden utilizar con todos los tipos de las bibliotecas mscorlib y Sistemade clases base de.NET.
Recursos Externos
Guía
Vea también
Conceptos
Aislar el código probado con Microsoft Fakes
Otros recursos
Blog de Peter Provost: Visual Studio 2012 cuñas
Vídeo (1h16): Código O.N.U-comprobable de prueba con Fakes en Visual Studio 2012