Usando shims para isolar seu aplicativo de outros assemblies para testes de unidade

Tipos de correção é uma das duas tecnologias que os usos de Framework de falsificação do Microsoft deixar facilmente isolar componentes no teste de ambiente.As correções desviam chamadas para métodos específicos para o código que você escreve como parte do seu teste.Muitos métodos retorna os resultados diferentes dependentes em condições externos, mas uma correção está sob o controle do seu teste e pode retornar resultados consistentes em cada chamada.Isso facilita escrever seus testes muito.

Use correções para isolar o código de assemblies que não são parte de sua solução.Para isolar componentes de sua solução de se, recomendamos que você usa modelos.

Para uma orientação da 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 Un- testavel com as falsificação no Visual Studio 2012

Neste tópico

Aqui é o que você aprenderá neste tópico:

Exemplo: O erro de Y2K

Como usar correções

  • Adicionar conjuntos de falsificação

  • Use ShimsContext

  • Escreva testando com correções

Correções para tipos diferentes de métodos

Alterar o comportamento padrão

Detectando acessa de ambiente

Concorrência

Chamando o método original do método corretivo

Restrições

Exemplo: O erro de Y2K

Vamos considerar um método que lança uma exceção º 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 porque 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: os programas que chamam diretamente nas APIs de banco de dados, se comunicam com os serviços da Web, são e assim por diante difícil para o teste de unidade porque sua lógica depende de 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 delegado definido pelo usuário.Os tipos de correção são gerados pelo gerador de falsificação, e usam os representantes, nós que chamamos tipos corretivos, para especificar as novas implementações de método.

O teste a 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

Hh549176.collapse_all(pt-br,VS.110).gifAdicionar conjuntos de falsificação

  1. No solution Explorer, expanda Referênciasdo seu projeto de teste de unidade.

    • Se você estiver trabalhando em Visual Basic, você deve selecionar Mostrar todos os arquivos na barra de ferramentas do Gerenciador de soluções, para ver a lista de referências.
  2. Selecione o assembly que contém as definições de classes que você deseja criar correções.Por exemplo, se você deseja calçar DateTime, selecione System.dll

  3. No menu de atalho, escolha Adicione o conjunto de falsificação.

Hh549176.collapse_all(pt-br,VS.110).gifUse ShimsContext

Quando usar corretivo digite uma estrutura de testes de unidade, você deve encapsular código de teste em ShimsContext para controlar o tempo de vida das correções.Se nós não exigimos isso, as correções duraram até que o Appdomain é desligado.A maneira mais fácil de criar ShimsContext é usando o método estático Create() conforme mostrado no código o seguir:

//unit test code
[Test]
public void Y2kCheckerTest() {
  using(ShimsContext.Create()) {
    ...
  } // clear all shims
}

É importante adequadamente exibir cada contexto corretivo.Em geral, chame sempre ShimsContext.Create em uma instrução de using para garantir que o esclarecimento apropriado de correções registrados.Por exemplo, você pode registrar uma correção para um método de teste que substituísse o método de DateTime.Now com um delegado que sempre retorna o primeiro de janeiro de 2000.Se você esquece desmarque a correção registrada no método de teste, o resto de ensaio retornaria sempre o primeiro de janeiro de 2000 porque o valor de DateTime.Now.Isso pode ser surpreendente e confuso.

Hh549176.collapse_all(pt-br,VS.110).gifEscreva um teste com correções

No seu 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 corretivos são compostos Fakes.Shim prefixando o 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 modo que em vez de chamada do 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 é descartada, algumas correções que você criou quando foi ativa é removida.A melhor maneira de fazer isso é dentro de uma instrução de using .

Você pode ver um erro de compilação que indica que o namespace de falsificação não existe.Este erro aparece as vezes quando existem outros erros de compilação.Corrigir os outros erros e desaparecerá.

Correções para tipos diferentes de métodos

Os tipos de correção permitem que você substitua todo o método .NET, incluindo métodos estáticos ou não métodos virtuais, com seus próprios representantes.

Hh549176.collapse_all(pt-br,VS.110).gifMétodos estáticos

As propriedades para anexar correções para métodos estáticos são colocadas em um tipo corretivo.Cada propriedade tem apenas um setter que pode ser usado para anexar um representante para o método de destino.Por exemplo, dado uma classe MyClass com um método estático MyMethod:

//code under test
public static class MyClass {
    public static int MyMethod() {
        ...
    }
}

Nós podemos anexar uma correção a MyMethod que sempre retorna 5:

// unit test code
ShimMyClass.MyMethod = () =>5;

Hh549176.collapse_all(pt-br,VS.110).gifMétodos de instância (para todas as instâncias)

Da mesma forma que os métodos estáticos, os métodos de instância podem ser calçados para todas as instâncias.As propriedades para anexar as correções são colocadas em um tipo aninhado chamado AllInstances para evitar confusão.Por exemplo, dado uma classe MyClass com um método de instância MyMethod:

// code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

Você pode anexar uma correção a MyMethod que sempre retorna 5, independentemente da instância:

// unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;

A estrutura gerado de tipo de 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 do delegado nesse caso.

Hh549176.collapse_all(pt-br,VS.110).gifMétodos como exemplo métodos (para uma instância de tempo de execução)

Os métodos de instância também podem ser calçados por destinos diferentes, com base no receptor de chamada.Isso permite que o mesmo método de instância para ter diferentes comportamentos por instância do tipo.As propriedades para configurar as correções são os métodos do tipo corretivo próprios de instância.Cada tipo corretivo instanciado também é associado com uma instância de um tipo " bruto " calçado.

Por exemplo, dado uma classe MyClass com um método de instância MyMethod:

// code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

Nós podemos configurar dois tipos de corretivos MyMethod como a primeira sempre retorna 5 e o segundo sempre retorna 10:

// unit test code
var myClass1 = new ShimMyClass()
{
    MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };

A estrutura gerado de tipo de 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 do 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, você geralmente pode simplesmente usar o tipo corretivo como é:

// unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // implicit cast retrieves the runtime
                         // instance

Hh549176.collapse_all(pt-br,VS.110).gifConstrutores

Construtores podem também ser calçados para anexar tipos corretivos a objetos futuros.Cada construtor é exposta como um construtor estático do método no tipo corretivo.Por exemplo, dado uma classe MyClass com um construtor que aceita um inteiro:

// code under test
public class MyClass {
    public MyClass(int value) {
        this.Value = value;
    }
    ...
}

Nós configuramos o tipo corretivo do construtor de modo 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 atualizado é necessária, quando o construtor que utiliza uma instância calçada como o argumento deve ser usado em correções do construtor somente:

// unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }

A estrutura gerado de tipo de ShimMyClass lembra o 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) { }
    ...
}

Hh549176.collapse_all(pt-br,VS.110).gifMembros de base

As propriedades corretivos de membros de base podem ser acessadas criando uma correção para o tipo base e passando a instância filho como um parâmetro para o construtor da classe baseia corretivo.

Por exemplo, dado uma classe MyBase com um método de instância MyMethod e um subtipo MyChild:

public abstract class MyBase {
    public int MyMethod() {
        ...
    }
}

public class MyChild : MyBase {
}

Nós 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 é convertido implicitamente à instância filho quando passado como um parâmetro para o construtor corretivo base.

A estrutura gerado de tipo de ShimMyChild e de ShimMyBase é parecida com o 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 { ... } }
}

Hh549176.collapse_all(pt-br,VS.110).gifConstrutores estáticos

Os tipos de correção expõe um método StaticConstructor estático para calçar o construtor estático de um tipo.Desde que os construtores estáticos são executadas somente uma vez, você precisará garantir que a correção está configurada antes que qualquer membro de tipo foi acessado.

Hh549176.collapse_all(pt-br,VS.110).gifFinalizers

Finalizers não é suportado em falsificação.

Hh549176.collapse_all(pt-br,VS.110).gifMétodos privados

O gerador de código de falsificação criará propriedades corretivos para os métodos particulares que possuem apenas visível na assinatura, os tipos de parâmetro.. de IE e o tipo de retorno visíveis.

Hh549176.collapse_all(pt-br,VS.110).gifAssociando interfaces

Quando um tipo calçado implementa uma interface, o gerador de código emite-se um método que permite que associa todos os membros da interface imediatamente.

Por exemplo, dado MyClass uma classe que implementa IEnumerable<int>:

public class MyClass : IEnumerable<int> {
    public IEnumerator<int> GetEnumerator() {
        ...
    }
    ...
}

Nós podemos calçar as implementações de IEnumerable<int> em MyClass chamando o método bind:

// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });

A estrutura gerado de tipo de ShimMyClass é parecida com o seguinte código:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public ShimMyClass Bind(IEnumerable<int> target) {
        ...
    }
}

Alterar o comportamento padrão

Cada tipo corretivo gerado contém uma instância da interface de IShimBehavior , através da propriedade de ShimBase<T>.InstanceBehavior .O comportamento é usado sempre que um cliente chama um membro de instância que não é calçado explicitamente.

Se o comportamento não foi definido explicitamente, usará a instância retornada pela propriedade estática de ShimsBehaviors.Current .Por padrão, essa propriedade retorna um comportamento que lança 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 seguinte trecho altera a correção a um comportamento que não faz nada ou retorna o valor padrão de retorno com que é, opção (T):

// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;

O comportamento também pode ser alterado global para todas as instâncias calçadas para 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 acessa de ambiente

É possível anexar um comportamento para todos os membros, incluindo métodos estáticos, de um determinado tipo atribuindo o comportamento de ShimsBehaviors.NotImplemented a propriedade estática Behavior de tipo correspondente corretivo:

// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();

Concorrência

Os tipos de correção aplicam-se a todos os segmentos em Appdomain e não se têm afinidade de threads.Este é um importante fato se você planejar usar um corredor de teste que suporta concorrência: os testes que envolvem tipos corretivos não podem executar simultaneamente.Esta propriedade não enfored em tempo de execução de falsificação.

Chamando o método original do método corretivo

Imagine que queremos escrever realmente o texto para o sistema de arquivos após validar o nome de arquivo passado para o 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 código a seguir:

// 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 para nulo, chame o método original e 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 .NET.

Recursos externos

Hh549176.collapse_all(pt-br,VS.110).gifOrientação

Teste para entrega contínuo com Visual Studio 2012 – capítulo 2: Testes de unidade: Testando o interior

Consulte também

Conceitos

Isolando código em teste com falsificação da Microsoft

Outros recursos

Blog de reitor de Peter: O Visual Studio 2012 correções

Exibição (1h16): Testando o código Un- testavel com as falsificação no Visual Studio 2012