Usando shims para isolar seu aplicativo de outros assemblies para testes de unidade
Tipos de correção é uma das tecnologias que a estrutura de falsificação do Microsoft deixar facilmente isolar componentes do no teste de ambiente.As correções desviam chamadas para os métodos específicos para codificar que você criou como parte de seu teste.Muitos métodos retornem os resultados diferentes dependentes em circunstâncias externos, mas uma correção estiver sob controle do teste e pode retornar resultados consistentes em cada chamada.Isso facilita os testes muito gravação.
Use correções para isolar seu código em assemblies que não fazem parte de sua solução.Para isolar componentes de sua solução de se, recomendamos que você use stub.
Para uma orientação de visão geral e de início rápido, consulte Isolando código em teste com falsificação da Microsoft
Requisitos
- Visual Studio Ultimate
Consulte Exibição (1h16): Testando o código não testavel com as falsificação no Visual Studio 2012
Neste tópico
Veja o que você aprenderá neste tópico:
Adicionar os assemblies de falsificação
Use ShimsContext
Escreva teste com correções
Correções para tipos diferentes dos métodos
Alterando o comportamento padrão
Chamando o método original do método corretivo
Exemplo: O bug de Y2K
Vamos observar um método que gerencie uma exceção o 1º de janeiro 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!");
}
}
Testar esse método é particularmente problemático como o programa depende de DateTime.Now, um método que depende do relógio do computador, um ambiente- dependente, método não determinística.Além disso, DateTime.Now é uma propriedade estática para que um tipo de stub não pode ser usado aqui.Esse problema é sintomático do problema de isolamento em testes de unidade: programas que chamam diretamente em APIs de base de dados, se comunicam com os serviços Web, são e assim por diante de hardware teste de unidade como sua lógica depende do ambiente.
Isso é onde os tipos de correção devem ser usados.Os tipos de correção fornecem um mecanismo para detour qualquer método .NET a um representante definido pelo usuário.Os tipos de correção codinome são gerados pelo gerador de falsificação, e usam os representantes, nós que chamamos tipos corretivos, para especificar novas implementações do método.
O teste seguir mostra como usar o tipo corretivo, ShimDateTime, para fornecer uma implementação 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();
}
Como usar correções
Adicionar os assemblies de falsificação
No Solution Explorer, expanda Referênciasde seu projeto de teste da unidade.
- Se você estiver trabalhando no Visual Basic, você deve selecionar Mostrar todos os arquivos na barra de ferramentas do Solution Explorer, para consultar a lista de referências.
Selecione o assembly que contém as definições de classes para a qual você deseja criar correções.Por exemplo, se você quiser calçar DateTime, System.dll selecione
No menu de atalho, escolha Adicione o assembly de falsificação.
Use ShimsContext
Quando usar corretivo digite em uma estrutura de teste de unidade, você deve incluir o código de teste em ShimsContext para controlar o tempo de vida das correções.Se isso não exigimos isso, as correções duraram até que o criar Appdomain será encerrado.A maneira mais fácil de criar ShimsContext é usando o método estático de Create() conforme mostrado no seguinte código:
//unit test code
[Test]
public void Y2kCheckerTest() {
using(ShimsContext.Create()) {
...
} // clear all shims
}
É crítica descartar corretamente cada contexto corretivo.Em geral, chame sempre ShimsContext.Create em uma instrução de using para garantir o limpando apropriado das correções registradas.Por exemplo, você pode registrar uma correção para um método de teste que substitui o método de DateTime.Now com um representante que sempre retorna o primeiro de janeiro de 2000.Se você esquecer desmarque a correção registrada no método de teste, o restante de execução do teste sempre retorna o primeiro de janeiro de 2000 porque o valor de DateTime.Now.Isso pode ser surpreendente e confusa.
Grave um teste com correções
No código de teste, insira um rodeio para o método que você deseja falsificar.Por exemplo:
[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
Os nomes de classe de correção são compostos pelo prefixo Fakes.Shim adicionado ao nome do tipo original.
As correções funcionam inserindo rodeios no código do aplicativo no teste.Onde uma chamada para o método original ocorre, as falsificação que o sistema executa um rodeio, de forma que em vez de chamar o método real, seu código corretivo é chamado.
Observe que os rodeios são criados e excluídos em tempo de execução.Você sempre deve criar um rodeio dentro de vida de ShimsContext.Quando é descartado, algumas correções que você criou quando estava ativo é descartada.A melhor maneira de fazer isso está dentro de uma instrução de using .
Talvez você encontre um erro de compilação que indica que o namespace de falsificação não existe.Esse erro aparece às vezes quando há outros erros de compilação.Corrigir os outros erros e desaparecerá.
Correções para tipos diferentes dos métodos
Os tipos de correção permitem que você substitua todo o método .NET, incluindo métodos estáticos ou métodos não virtuais, com seus próprios delegados.
Métodos estáticos
As propriedades para anexar correções os métodos estáticos são colocados em um tipo corretivo.Cada propriedade tem apenas um setters que pode ser usado para anexar um representante para o método de destino.Por exemplo, em uma classe MyClass com um método estático MyMethod:
//code under test
public static class MyClass {
public static int MyMethod() {
...
}
}
Podemos anexar uma correção para MyMethod que sempre retorna 5:
// unit test code
ShimMyClass.MyMethod = () =>5;
Métodos de instância (para todas as instâncias)
De modo semelhante aos métodos estáticos, os métodos de instância pode ser calçados para todas as instâncias.As propriedades para anexar as correções são colocados em um tipo aninhado nomeada AllInstances para evitar confusão.Por exemplo, em uma classe MyClass com um método MyMethodda instância:
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Você pode anexar uma correção para MyMethod que sempre retorna 5, independentemente da instância:
// unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;
A estrutura gerada de tipo aspectos de ShimMyClass como o seguinte código:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public static class AllInstances {
public static Func<MyClass, int>MyMethod {
set {
...
}
}
}
}
Observe que as falsificação passam a instância de tempo de execução como o primeiro argumento de delegação nesse caso.
A instância métodos (para uma instância de tempo de execução)
Os métodos da instância também podem ser calçados por delegados diferentes, com base no destinatário de chamada.Isso permite que o mesmo método de instância para ter diversos comportamentos pela instância do tipo.As propriedades para configurar as correções são os métodos de tipo corretivo próprios da instância.Cada tipo corretivo instanciado é associado também bruto com uma instância de um tipo calçado.
Por exemplo, em uma classe MyClass com um método MyMethodda instância:
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Podemos configure dois tipos de MyMethod corretivos de modo que primeiro sempre retorna 5 e a segunda sempre retorna 10:
// unit test code
var myClass1 = new ShimMyClass()
{
MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };
A estrutura gerada de tipo aspectos de ShimMyClass como o seguinte código:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public Func<int> MyMethod {
set {
...
}
}
public MyClass Instance {
get {
...
}
}
}
A instância calçada real de tipo pode ser acessada através da propriedade da instância:
// unit test code
var shim = new ShimMyClass();
var instance = shim.Instance;
O tipo corretivo também tem uma conversão implícita para o tipo calçado portanto, normalmente é possível simplesmente usar o tipo corretivo como é:
// unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // implicit cast retrieves the runtime
// instance
Construtores
Os construtores também podem ser calçados para anexar tipos corretivos a objetos futuros.Cada construtor é exposto como um construtor de método estático no tipo corretivo.Por exemplo, em uma classe MyClass com um construtor que usa um inteiro:
// code under test
public class MyClass {
public MyClass(int value) {
this.Value = value;
}
...
}
Configuramos o tipo corretivo do construtor de forma que cada instância futura retorna -5 quando o getter do valor é chamado, independentemente do valor no construtor:
// unit test code
ShimMyClass.ConstructorInt32 = (@this, value) => {
var shim = new ShimMyClass(@this) {
ValueGet = () => -5
};
};
Observe que cada tipo corretivo expõe dois construtores.O construtor padrão deve ser usado quando uma instância atualizada for necessária, quando o construtor que usa uma instância calçada como o argumento deve ser usado em correções de construtor apenas:
// unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }
A estrutura gerada do tipo de ShimMyClass se assemelha ao código followoing:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass>
{
public static Action<MyClass, int> ConstructorInt32 {
set {
...
}
}
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }
...
}
Membros de base
As propriedades corretivos de membros de base podem ser acessadas criando uma correção para o tipo de base e passando a instância filho como um parâmetro para o construtor de corretivo baseia a classe.
Por exemplo, em uma classe MyBase com um método MyMethod da instância e um subtipo MyChild:
public abstract class MyBase {
public int MyMethod() {
...
}
}
public class MyChild : MyBase {
}
Podemos configurar uma correção de MyBase criando uma nova correção de ShimMyBase :
// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };
Observe que o tipo corretivo filho será convertido implicitamente a instância filho quando passado como um parâmetro para o construtor corretivo de base.
A estrutura gerada do tipo de ShimMyChild e de ShimMyBase se assemelha ao seguinte código:
// 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 { ... } }
}
Construtores estáticos
Os tipos de correção expõe um método estático StaticConstructor para calçar o construtor estática de um tipo.Como os construtores estáticos são executados apenas uma vez, você precisa assegurar que a correção está configurada antes que qualquer membro do tipo seja acessado.
Finalizers
Finalizers não tem suporte em falsificação.
Métodos privados
O gerador de código de falsificação criará propriedades corretivos para métodos particulares que têm visível somente na assinatura, isso é tipos de parâmetro e tipo de retorno visíveis.
Associando interfaces
Quando um tipo calçado implementa uma interface, o gerador de código emite um método que permite que associa todos os membros dessa interface imediatamente.
Por exemplo, em uma classe MyClass que implementa IEnumerable<int>:
public class MyClass : IEnumerable<int> {
public IEnumerator<int> GetEnumerator() {
...
}
...
}
Podemos calçar as implementações de IEnumerable<int> em MyClass chamando o método de associação:
// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });
A estrutura gerada do tipo de ShimMyClass se assemelha ao seguinte código:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public ShimMyClass Bind(IEnumerable<int> target) {
...
}
}
Alterando o comportamento padrão
Cada tipo corretivo gerado contém uma instância da interface de IShimBehavior , por meio da propriedade de ShimBase<T>.InstanceBehavior .O comportamento é usado sempre que um cliente chama um membro da instância do que não é calçado explicitamente.
Se o comportamento não foi definido explicitamente, o usará a instância retornada pela propriedade estática de ShimsBehaviors.Current .Por padrão, esta propriedade retorna um comportamento que gerou uma exceção de NotImplementedException .
Esse comportamento pode ser alterado a qualquer momento definindo a propriedade de InstanceBehavior em qualquer instância corretivo.Por exemplo, o trecho a seguir altera a correção para um comportamento que não faça nada ou retorna o valor padrão de retorno - ou seja, default (T):
// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;
O comportamento também pode ser modificado global para todas as instâncias calçadas para que a propriedade de InstanceBehavior não foi definida explicitamente definindo a propriedade 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;
Detectando e de ambiente
É possível anexar um comportamento a todos os membros, incluindo métodos estáticos de um tipo específico, atribuindo o comportamento de ShimsBehaviors.NotImplemented a propriedade estática Behavior do tipo corretivo correspondente:
// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();
Simultaneidade
Os tipos de correção se aplicam a todos os threads em Appdomain e não têm se a afinidade do thread.Este é um fato importante se você planeja usar um executor de teste que oferece suporte a simultaneidade: os testes que envolvem tipos corretivos não podem ser executadas simultaneamente.Essa propriedade não enfored em tempo de execução de falsificação.
Chamando o método original do método corretivo
Imagine que desejamos para gravar realmente o texto no sistema de arquivos depois de ter validado o nome de arquivo transmitido ao método.Nesse caso, é desejaríamos para chamar o método original no meio do método corretivo.
A primeira abordagem para resolver esse problema é envolver uma chamada para o método original usando um representante e ShimsContext.ExecuteWithoutShims() como no seguinte código:
// unit test code
ShimFile.WriteAllTextStringString = (fileName, content) => {
ShimsContext.ExecuteWithoutShims(() => {
Console.WriteLine("enter");
File.WriteAllText(fileName, content);
Console.WriteLine("leave");
});
};
Outra abordagem é definir a correção como nulo, chame o método original e para restaurar a correção.
// 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;
Restrições
As correções não podem ser usadas em todos os tipos de biblioteca mscorlib e Sistemada classe base do .NET.
Recursos externos
Orientação
Consulte também
Conceitos
Isolando código em teste com falsificação da Microsoft
Outros recursos
O blog de reitor de Peter: Correções do Visual Studio 2012
Exibição (1h16): Testando o código não testavel com as falsificação no Visual Studio 2012