Exercício – depurar com o Visual Studio

Concluído

É hora de colocar em prática seus novos conhecimentos de depuração. É seu primeiro dia de trabalho e você quer colocar suas habilidades de depuração do .NET para funcionar corrigindo um bug no principal produto da empresa, uma calculadora Fibonacci.

Criar um projeto .NET de exemplo para depuração

Para configurar o Visual Studio para depuração do .NET, primeiro precisamos de um projeto do .NET. O Visual Studio fornece muitos modelos iniciais que facilitam a criação de um projeto.

  1. No Visual Studio, selecione Arquivo>Novo>Projeto.

  2. Na caixa de diálogo Criar um novo Projeto , selecione Aplicativo de Console e escolha Avançar.

  3. Nomeie o projeto DotNetDebugging e escolha o local onde você deseja salvar. Deixe os outros valores em seus padrões e selecione Avançar.

  4. Selecione Criar na tela final.

O Visual Studio cria o projeto console para nós usando o modelo selecionado. Depois que o projeto for carregado, abra Program.cs selecionando-o.

Adicionar a lógica do programa Fibonacci

Nosso projeto atual escreve uma mensagem de "Olá, Mundo" no console, o que não oferece muito para depurar. Vamos usar um programa do .NET curto para calcular o enésimo número da sequência Fibonacci.

A sequência Fibonacci é um conjunto de números que começa com 0 e 1, em que cada número seguinte é a soma dos dois anteriores. A sequência continua conforme mostrado aqui:

0, 1, 1, 2, 3, 5, 8, 13, 21...

O código de exemplo a seguir contém um bug, portanto, vamos usar as ferramentas de depuração do Visual Studio para diagnosticar e resolver o problema.

  1. Substitua o conteúdo de Program.cs pelo seguinte código:
int result = Fibonacci(5);
Console.WriteLine(result);

static int Fibonacci(int n)
{
    Console.WriteLine("The output is: ");
    int n1 = 0;
    int n2 = 1;
    int sum;

    for (int i = 2; i < n; i++)
    {
        sum = n1 + n2;
        n1 = n2;
        n2 = sum;
    }

    return n == 0 ? n1 : n2;
}

Observação

Esse código contém um erro que depuramos posteriormente neste módulo. Não recomendamos o uso dele em nenhum aplicativo Fibonacci crítico até que o bug seja corrigido.

  1. Salve o arquivo com Ctrl+S para Windows e Linux. Selecione Cmd+S para Mac.

  2. Vejamos como o código atualizado funciona antes de depurá-lo. Execute o programa pressionando o botão de início verde na barra de comandos do Visual Studio.

  3. No final da saída do console de depuração, você pode ver que o programa escreve 3 no console e, em seguida, sai com o código 0. Geralmente, o código de saída 0 indica que o programa foi executado e encerrado sem apresentar falhas. No entanto, há uma diferença entre apresentar falhas e retornar o valor correto.

Janela do terminal com saída do programa modificada.

Neste caso, solicitamos que o programa calcule o quinto valor da sequência Fibonacci:

0, 1, 1, 2, 3, 5, 8, 13, 21...

O quinto valor nessa lista é 5, mas o programa retornou 3. Vamos usar o depurador para diagnosticar e corrigir esse erro.

Usar pontos de interrupção e a execução passo a passo

  1. Adicione um ponto de interrupção clicando na margem esquerda na linha 1 em int result = Fibonacci(5);.

  2. Inicie a depuração novamente. O programa começa a ser executado. Ele é interrompido (a execução é pausada) na linha 1 devido ao ponto de interrupção que você definiu. Use os controles do depurador para entrar na função Fibonacci().

    Captura de tela do botão Entrar.

Verificar estado das variáveis

Agora, leve algum tempo para inspecionar os valores das diferentes variáveis usando a janela Locals .

Captura de tela do painel de Locais.

  • Qual é o valor mostrado para o parâmetro n?
  • No início da execução da função, quais são os valores das variáveis locais n1, n2 e sum?
  1. Em seguida, avançamos para o loop for usando o controle de depurador Passo a passo.

    Captura de tela do botão de avanço.

  2. Continue avançando até chegar à primeira linha dentro do loop for. A linha que diz:

    sum = n1 + n2;
    

Observação

Você pode observar que mover-se pela linha for(...) {} requer várias etapas nos comandos. Isso ocorre porque há várias instruções nessa linha. Quando intervém, você passa para a instrução seguinte no código. Normalmente, há uma instrução por linha. Se não for esse o caso, você precisará de várias etapas para passar para a próxima linha.

Refletir sobre o código

Uma parte importante da depuração é parar e fazer suposições sobre o que você acha que as partes do código (funções e blocos, como os loops) estão tentando fazer. Não há problema se você não tem certeza, isso faz parte do processo de depuração. Mas estar ativamente envolvido no processo de depuração ajuda a localizar bugs muito mais rapidamente.

Antes de continuar, precisamos nos lembrar de que a sequência Fibonacci é um conjunto de números que começa com 0 e 1, em que cada número seguinte é a soma dos dois anteriores.

Isso significa que:

Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1 (0 + 1)
Fibonacci(3) = 2 (1 + 1)
Fibonacci(4) = 3 (1 + 2)
Fibonacci(5) = 5 (2 + 3)

Após entender a definição e analisar o loop for, podemos deduzir que:

  1. O loop conta de 2 até n (o número da sequência Fibonacci que estamos buscando).
  2. Se n for menor que 2, o loop nunca será executado. A instrução return no final da função retorna 0 se n for 0 e 1 se n for 1 ou 2. Esses valores são os valores zero, primeiro e segundo na série Fibonacci, por definição.
  3. O caso mais interessante é quando n é maior que 2. Nesses casos, o valor atual é definido como a soma dos dois valores anteriores. Portanto, para esse loop, n1 e n2 são os dois valores anteriores, e sum é o valor para a iteração atual. Por causa dessa lógica, sempre que descobrimos a soma dos dois valores anteriores e a definimos como sum, atualizamos nossos valores n1 e n2.

Não precisamos pensar muito além disso. Podemos confiar um pouco em nosso depurador. Mas vale a pena pensar no código para ver se ele faz o que esperamos e ter mais informações quando isso não acontece.

Localizar o bug com pontos de interrupção

Percorrer seu código pode ser útil, mas entediante. Especialmente quando você está trabalhando com loops ou outro código que é chamado repetidamente. Em vez de percorrer o loop repetidamente, podemos definir um novo ponto de interrupção na primeira linha do loop.

É importante inserir os pontos de interrupção de modo estratégico. Estamos interessados, sobretudo, no valor de sum, já que ele representa o valor máximo atual de Fibonacci. Então, vamos colocar nosso ponto de interrupção na linha depoissum de definido.

  1. Adicione um segundo ponto de interrupção na linha 14.

    Captura de tela mostrando um segundo ponto de interrupção sendo definido.

    Observação

    Se você observar que continua executando o código e percorrendo uma linha ou duas, poderá facilmente atualizar seus pontos de interrupção para linhas mais eficientes.

  2. Agora que temos um bom ponto de interrupção definido no loop, selecione Continuar nos controles do depurador para avançar até que o ponto de interrupção seja atingido. Ao observarmos nossas variáveis locais, vemos as seguintes linhas:

    n [int]: 5
    n1 [int]: 0
    n2 [int]: 1
    sum [int]: 1
    i [int]: 2
    

    Todas essas linhas parecem corretas. Na primeira vez que o loop é executado, a sum dos dois valores anteriores é 1. Em vez de passar linha por linha, podemos aproveitar nossos pontos de interrupção para ir direto até a próxima execução do loop.

  3. Selecione Continuar para continuar o fluxo do programa até que o próximo ponto de interrupção seja atingido, que será na próxima passagem pelo loop.

    Observação

    Não se preocupe muito em ignorar o bug ao usar Continuar. Você deve esperar que você possa depurar por meio do código várias vezes para encontrar o problema. Geralmente, o mais rápido é executá-lo algumas vezes, em vez de ser muito cauteloso ao percorrê-lo.

    Desta vez, vemos os seguintes valores:

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 1
    sum [int]: 2
    i [int]: 3
    

    Esses valores ainda fazem sentido? Parece que sim. Para o terceiro número Fibonacci, esperamos ver nossa sum igual a 2, o que acontece.

  4. Selecione Continuar para loop novamente.

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 2
    sum [int]: 3
    i [int]: 4
    

    O resultado está correto. O quarto valor na série deve ser 3.

  5. Neste momento, você pode se questionar se imaginou toda a situação do bug e se o código já estava certo desde o início. Vamos manter essa dúvida e executar o loop pela última vez. Selecione Continuar mais uma vez.

    O programa terminou de ser executado e a saída é 3! Nosso resultado está incorreto.

    Agora sabemos que o código executa o loop corretamente até que i seja igual a 4, mas ele é encerrado antes de calcular o valor final. Reduzimos onde está o bug.

  6. Vamos definir mais um ponto de interrupção na linha 18, em que está escrito:

    return n == 0 ? n1 : n2;
    

    Esse ponto de interrupção nos permite inspecionar o estado do programa antes da saída da função. Já aprendemos tudo o que podemos esperar de nossos pontos de interrupção anteriores nas linhas 1 e 13, para que possamos limpá-los.

  7. Remova os pontos de interrupção anteriores das linhas 1 e 13. Selecione os pontos de interrupção na margem ao lado dos números de linha ou desmarque as caixas de seleção do ponto de interrupção para as linhas 1 e 13 no painel pontos de interrupção no canto inferior esquerdo.

    Captura de tela mostrando os pontos de interrupção listados no painel de pontos de interrupção.

    Agora que entendemos melhor o que está acontecendo e definimos um ponto de interrupção projetado para capturar nosso programa no comportamento inadequado. Agora devemos poder capturar esse bug!

  8. Inicie o depurador uma última vez.

    n [int]: 5
    n1 [int]: 2
    n2 [int]: 3
    sum [int]: 3
    

    Solicitamos especificamente Fibonacci(5) e temos Fibonacci(4), o que está incorreto. Essa função retorna n2, e cada iteração de loop calcula o valor de sum e define n2 igual a sum.

    Com base nessas informações e em nossa execução de depuração anterior, podemos ver que o loop foi encerrado quando i era 4, e não 5.

    Vamos examinar nossa instrução loop for um pouco mais de perto.

    for (int i = 2; i < n; i++)
    

    Essa lógica faz com que o programa saia assim que a parte superior do loop for i igual a n. Isso significa que o código de loop não é executado para o caso em que i é igual a n. Parece que queríamos uma execução até i <= n, porém, em vez disso:

    for (int i = 2; i <= n; i++)
    

    Com essa alteração, seu programa atualizado deve se parecer com este exemplo:

    int result = Fibonacci(5);
    Console.WriteLine(result);
    
    static int Fibonacci(int n)
    {
        Console.WriteLine("The output is: ");
        int n1 = 0;
        int n2 = 1;
        int sum;
    
        for (int i = 2; i <= n; i++)
        {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
    
        return n == 0 ? n1 : n2;
    }
    
  9. Interrompa a sessão de depuração se ainda não tiver feito isso.

  10. Faça a alteração anterior na linha 11 e deixe o ponto de interrupção na linha 18.

  11. Reinicie o depurador. Desta vez, quando atingimos o ponto de interrupção na linha 18, vemos os seguintes valores:

    n [int]: 5
    n1 [int]: 3
    n2 [int]: 5
    sum [int]: 5
    

    Oi! Parece que deu certo! Ótimo trabalho, você salvou o dia da Fibonacci, Inc.!

  12. Selecione Continuar apenas para garantir que o programa retorne o valor correto.

    5
    The program '[105260] DotNetDebugging.dll' has exited with code 0 (0x0).
    

    E ele retorna a saída certa.

Você conseguiu! Você depurou algum código que não escreveu usando o depurador do .NET no Visual Studio.

Na próxima unidade, você aprenderá a tornar o código que você escreve mais fácil de depurar usando os recursos de registro em log e rastreamento integrados ao .NET.