Exportar (0) Imprimir
Expandir Tudo

Testando o intestável com Microsoft Fakes

Bruno Sonnino

Agosto 2013

Dn412780.060DE5057573180CEC6D227C6D3E2207(pt-br,MSDN.10).png

Introdução

Muitas vezes devemos fazer mudanças em programas que estão em produção há muito tempo e que não foram desenvolvidos com boas práticas de programação. Nesta hora, nossa primeira ideia é correr o mais rápido possível para longe disso: a possibilidade de dar problemas é muito grande e mexer no código é quase impossível – estamos trabalhando com um castelo de cartas, onde o menor movimento pode derrubar tudo.

A ideia de refatorar (ou mesmo reescrever) o código vem de longe, mas onde está o tempo para fazer isso? Os projetos são sempre para ontem e isto não é prioridade, afinal está funcionando, não? Por que mexer no programa?

Podemos melhorar um pouco a situação criando testes unitários para as mudanças que devemos fazer, mas como implementar isso? O programa está cheio de dependências, as regras de negócio estão misturadas com a visualização, os métodos são longos e complicados.

O máximo que poderíamos fazer aqui são testes de integração, que por serem difíceis de implementar e demorados de executar, serão abandonados rapidamente. O que fazer nesta hora? A solução está à mão, a Microsoft implementou um projeto da Microsoft Research, o Moles, e colocou-o no Visual Studio 2012, com o nome de Fakes, para que possamos criar testes para qualquer coisa, inclusive classes do .Net Framework.

Com o Fakes, podemos criar testes unitários, que rodam rapidamente e não dependem de nada, nem do sistema operacional, máquina ou banco de dados. Aqui cabe uma observação: não é porque o Fakes permite testar qualquer coisa que devemos relaxar no nosso código – o ideal é usar boas práticas de programação para projetos novos e não precisar do Fakes para simular dependências que não deveriam existir. Assim, quando estiver criando código novo, tente fazê-lo para não precisar do Fakes, use-o apenas quando isso for indispensável.

O problema

Para mostrar como usamos o Fakes, iremos usar um pequeno projeto que tem apenas uma janela com um TextBlock:

<Window x:Class="FakesTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock x:Name="TxtDate"/>
    </Grid>
</Window>

Quando a janela é inicializada, o TextBlock é alimentado com a data atual:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        TxtDate.Text = string.Format("A data atual é {0:d}", DateTime.Now);
    }
}

Devemos fazer uma mudança neste código, para colocar também o dia da semana no TextBlock, como em “A data atual é 2/8/2013 (sexta-feira)”. Como queremos usar boas práticas, iremos criar testes unitários para o projeto. Mas como fazer isso? O código está misturado na View e tem a dependência de DateTime, uma classe do .Net Framework.

Criando o projeto de testes

Vamos criar nosso projeto de testes. No Solution Explorer, selecione a solução, dê um clique com o botão direito do mouse e selecione Add/New Project. Selecione Test/Unit Test Project e chame-o de FakesTest.Tests. Adicione nele uma referência a nossa solução. Renomeie a classe UnitTest1.cs para MainWindowTests.cs.

Aqui começa nosso problema: queremos testar o que está sendo mostrado no TextBlock. Para isso, devemos criar uma janela, inicializá-la e ver o seu conteúdo. Nada fácil para fazer com testes unitários.

Aqui entra o Fakes. No projeto de testes, nas referências, selecione a referência ao projeto principal e clique com o botão direito e selecione “Add Fakes Assembly”. É adicionada uma nova referência a FakesTest.Fakes – esta referência irá criar os fakes para a janela e para seus componentes. Para usá-los nos testes, devemos adicionar as referências a System.Xaml, PresentationCore, PresentationFramework e WindowsBase.

Em seguida, precisamos criar mais um fake para a classe DateTime. Selecione a biblioteca System nas referências e clique com o botão direito, selecionando “Add Fakes Assembly”. Agora que já temos todo o nosso ambiente “virtualizado”, podemos criar o teste unitário.

Para usar os componentes gerados pelo Fakes, devemos envolver sua chamada numa cláusula Using, usando um ShimsContext:

using (ShimsContext.Create())
{
    ….
}

Em seguida, iremos determinar o comportamento da classe DateTime, quando a propriedade Now for chamada:

ShimDateTime.NowGet = () => new DateTime(2013,1,1);

Para acessarmos a classe DateTime criada pelo Fakes, usamos a classe ShimDateTime. A linha acima diz o seguinte: quando for usado o Get da propriedade Now (NowGet), retorne a data 1/1/2013. A partir daí, nosso teste fica sendo igual a qualquer outro teste unitário:

[TestMethod]
public void CriaJanela_TextBlockTemValorDataAtual()
{
    using (ShimsContext.Create())
    {
        ShimDateTime.NowGet = () => new DateTime(2013,1,1);
        var window = new MainWindow();
        var mainGrid = (Grid)window.Content;
        var textBlock = (TextBlock) mainGrid.Children[0];
        Assert.AreEqual("A data atual é 01/01/2013",textBlock.Text);
    }
}

Criamos a janela e verificamos se o TextBlock tem a data que passamos no fake. Ao executar os testes com Ctrl+R+T, vemos que o teste passa. Até aqui estamos cobertos. Vamos fazer a alteração no nosso código.

Fazendo a mudança no programa

Como já temos o teste, podemos alterá-lo para a mudança que iremos fazer:

[TestMethod]
public void CriaJanela_TextBlockTemValorDataAtual()
{
    using (ShimsContext.Create())
    {
        ShimDateTime.NowGet = () => new DateTime(2013,1,1);
        var window = new MainWindow();
        var mainGrid = (Grid)window.Content;
        var textBlock = (TextBlock) mainGrid.Children[0];
        Assert.AreEqual("A data atual é 01/01/2013 (terça-feira)",textBlock.Text);
    }
}

Fizemos a mudança no teste, mas ainda não mudamos nosso código. Se rodarmos o teste agora, ele irá falhar:

Assert.AreEqual failed. Expected:<A data atual é 01/01/2013 (terça-feira)>. Actual:<A data atual é 01/01/2013>.

Devemos fazer a mudança no código:

public MainWindow()
{
    InitializeComponent();
    TxtDate.Text = string.Format("A data atual é {0:d} ({0:dddd})", DateTime.Now);
}

Ao executar o teste, ele passa – nossa modificação está completa e funcionando. Para completar o ciclo Red-Green-Refactor do TDD, podemos refatorar nosso código, extraindo a função da atribuição:

public MainWindow()
{
    InitializeComponent();
    TxtDate.Text = GetTextDate();
}

private static string GetTextDate()
{
    return string.Format("A data atual é {0:d} ({0:dddd})", DateTime.Now);
}

Rodamos os testes e eles continuam rodando. A mudança está completa.

Conclusões

Como pudemos ver, o Fakes ajuda bastante quando temos código legado que, pelas suas dependências, não permite que criemos testes unitários de maneira fácil. O que fizemos aqui foi simular a criação de uma janela, a atribuição de um valor a um TextBlock, atribuir um valor à data atual, sem precisar de nenhum arranjo especial.

Isso não quer dizer que devemos usar este recurso sempre – o uso do Fakes para simular dependências deve só ser usado como último recurso, quando o código já existe e não permite que seja quebrado facilmente. Ele pode ser usado como um ponto de partida para o verdadeiro refatoramento do programa: no nosso caso, deveríamos nos desvincular da dependência da janela, usando o padrão de projeto MVVM e também de System.DateTime, usando uma interface (que poderíamos chamar de IDateProvider), mas isso já é assunto para um outro artigo. Até lá!

A Microsoft está realizando uma pesquisa online para saber sua opinião sobre o site do MSDN. Se você optar por participar, a pesquisa online lhe será apresentada quando você sair do site do MSDN.

Deseja participar?
Mostrar:
© 2014 Microsoft