Partilhar via


Depuração para completos iniciantes

Sem falhas, o código que escrevemos como desenvolvedores de software nem sempre faz o que esperávamos que fizesse. Às vezes faz algo completamente diferente! Quando o inesperado acontece, a próxima tarefa é descobrir o porquê e, embora possamos ficar tentados a ficar olhando para nosso código por horas, é mais fácil e eficiente usar uma ferramenta de depuração ou depurador.

Um depurador, infelizmente, não é algo que pode revelar magicamente todos os problemas ou "bugs" em nosso código. Depuração significa executar seu código passo a passo em uma ferramenta de depuração como o Visual Studio, para encontrar o ponto exato onde você cometeu um erro de programação. Em seguida, você entende quais correções precisa fazer em seu código e as ferramentas de depuração geralmente permitem que você faça alterações temporárias para que você possa continuar executando o programa.

Usar um depurador de forma eficaz também é uma habilidade que leva tempo e prática para aprender, mas é, em última análise, uma tarefa fundamental para todo desenvolvedor de software. Neste artigo, apresentamos os princípios fundamentais da depuração e fornecemos dicas para você começar.

Esclareça o problema fazendo-se as perguntas certas

Isso ajuda a esclarecer o problema que você encontrou antes de tentar corrigi-lo. Esperamos que já tenhas encontrado um problema no teu código, caso contrário, não estarias aqui a tentar descobrir como depurá-lo! Portanto, antes de começar a depuração, certifique-se de ter identificado o problema que pretende resolver:

  • O que você esperava que seu código fizesse?

  • O que aconteceu em vez disso?

    Se você encontrar um erro (exceção) ao executar seu aplicativo, pode ser uma coisa boa! Uma exceção é um evento inesperado encontrado ao executar código, normalmente um erro de algum tipo. Uma ferramenta de depuração pode levá-lo ao local exato em seu código onde a exceção ocorreu e pode ajudá-lo a investigar possíveis correções.

    Se algo mais aconteceu, qual é o sintoma do problema? Você já suspeita onde esse problema ocorreu no seu código? Por exemplo, se o código exibir algum texto, mas o texto estiver incorreto, você saberá que seus dados estão ruins ou que o código que define o texto de exibição tem algum tipo de bug. Ao percorrer o código em um depurador, você pode examinar cada alteração em suas variáveis para descobrir exatamente quando e como valores incorretos são atribuídos.

Examine suas suposições

Antes de investigar um bug ou um erro, pense nas suposições que fizeram você esperar um determinado resultado. Suposições ocultas ou desconhecidas podem atrapalhar a identificação de um problema, mesmo quando você está olhando diretamente para a causa do problema em um depurador. Você pode ter uma longa lista de suposições possíveis! Aqui estão algumas perguntas para se fazer para desafiar suas suposições.

  • Você está usando a API certa (ou seja, o objeto, função, método ou propriedade certo)? Uma API que você está usando pode não fazer o que você acha que faz. (Depois de examinar a chamada de API no depurador, corrigi-la pode exigir uma consulta à documentação para localizar a API correta.)

  • Você está usando uma API corretamente? Talvez você tenha usado a API certa, mas não a usou da maneira certa.

  • O seu código contém algum erro de digitação? Alguns erros de digitação, como um simples erro ortográfico de um nome de variável, podem ser difíceis de ver, especialmente ao trabalhar com idiomas que não exigem que as variáveis sejam declaradas antes de serem usadas.

  • Você fez uma alteração no seu código e assumiu que ele não está relacionado ao problema que você está vendo?

  • Você esperava que um objeto ou variável contivesse um determinado valor (ou um certo tipo de valor) diferente do que realmente aconteceu?

  • Você sabe a intenção do código? Muitas vezes, é mais difícil depurar o código de outra pessoa. Se não for o seu código, é possível que você precise gastar tempo aprendendo exatamente o que o código faz antes de poder depurá-lo efetivamente.

    Dica

    Ao escrever código, comece pequeno e comece com o código que funciona! (Um bom exemplo de código é útil aqui.) Às vezes, é mais fácil corrigir um conjunto grande ou complicado de código começando com um pequeno pedaço de código que demonstra a tarefa principal que você está tentando alcançar. Em seguida, você pode modificar ou adicionar código incrementalmente, testando em cada ponto a existência de erros.

Ao questionar suas suposições, você pode reduzir o tempo necessário para encontrar um problema em seu código. Você também pode reduzir o tempo necessário para corrigir um problema.

Percorra o código no modo de depuração para encontrar onde o problema ocorreu

Quando você normalmente executa um aplicativo, você vê erros e resultados incorretos somente depois que o código é executado. Um programa também pode ser encerrado inesperadamente sem dizer o porquê.

Quando você executa um aplicativo dentro de um depurador, também chamado de modo de depuração , o depurador monitora ativamente tudo o que está acontecendo enquanto o programa é executado. Isso também permite que o utilizador pause a aplicação a qualquer momento para examinar o seu estado e, em seguida, percorrer o seu código linha por linha para observar cada detalhe à medida que acontece.

No Visual Studio, você entra no modo de depuração usando F5 (ou o comando do menu Depurar>Iniciar Depuração ou o botão Iniciar Depuraçãoícone mostrando o botão Iniciar Depuração. na Barra de Ferramentas Depurar). Se ocorrer alguma exceção, o Auxiliar de Exceção do Visual Studio levará você ao ponto exato onde a exceção ocorreu e fornecerá outras informações úteis. Para obter mais informações sobre como lidar com exceções em seu código, consulte Técnicas e ferramentas de depuração.

Se você não obteve uma exceção, provavelmente tem uma boa ideia de onde procurar o problema em seu código. Quando usas os pontos de interrupção com o depurador, tens a oportunidade de examinar o teu código mais cuidadosamente. Os pontos de interrupção são a funcionalidade mais básica e essencial da depuração fiável. Um ponto de interrupção indica onde o Visual Studio deve pausar seu código em execução para que você possa examinar os valores das variáveis, ou o comportamento da memória, a sequência na qual o código é executado.

No Visual Studio, você pode definir rapidamente um ponto de interrupção clicando na margem esquerda ao lado de uma linha de código. Ou coloque o cursor sobre uma linha e pressione F9.

Para ajudar a ilustrar esses conceitos, levamos você através de alguns exemplos de código que já tem vários bugs. Estamos usando C#, mas os recursos de depuração se aplicam ao Visual Basic, C++, JavaScript, Python e outras linguagens suportadas. Código de exemplo para Visual Basic também é fornecido, mas capturas de tela estão em C#.

Criar um aplicativo de exemplo (com alguns bugs)

Em seguida, você cria um aplicativo que tem alguns bugs.

  1. Você deve ter o Visual Studio instalado e o .NET desktop development workload instalado.

    Se você ainda não instalou o Visual Studio, vá para a página de downloads do Visual Studio para instalá-lo gratuitamente.

    Se você precisar instalar a carga de trabalho, mas já tiver o Visual Studio, selecione Ferramentas >Obter Ferramentas e Recursos. O instalador do Visual Studio é iniciado. Escolha a carga de trabalho de desenvolvimento de desktop .NET e, em seguida, escolha Modificar.

  2. Abra o Visual Studio.

    Na janela Iniciar, escolha Criar um novo projeto. Digite console na caixa de pesquisa, selecione C# ou Visual Basic como a linguagem e escolha Aplicação de Console para .NET. Escolha Próximo. Digite ConsoleApp_FirstApp como o nome do projeto e selecione Avançar.

    Se você usar um nome de projeto diferente, precisará modificar o valor do namespace para corresponder ao nome do projeto ao copiar o código de exemplo.

    Escolha a estrutura de destino recomendada ou .NET 8, depois selecione Criar.

    Se você não vir o modelo de projeto do Console App para .NET, vá para Ferramentas >Obter Ferramentas e Recursos, que abre o Visual Studio Installer. Escolha o de trabalho de desenvolvimento da área de trabalho .NET e, em seguida, escolha Modificar.

    O Visual Studio cria o projeto de console, que aparece em Gerenciador de Soluções no painel direito.

  3. No Program.cs (ou Program.vb), substitua todo o código padrão pelo código a seguir. Primeiro, selecione o separador do idioma correto, C# ou Visual Basic.

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp_FirstApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Welcome to Galaxy News!");
                IterateThroughList();
                Console.ReadKey();
            }
    
            private static void IterateThroughList()
            {
                var theGalaxies = new List<Galaxy>
            {
                new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')},
                new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')},
                new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')},
                new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')},
                new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')},
                new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')}
            };
    
                foreach (Galaxy theGalaxy in theGalaxies)
                {
                    Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
                }
    
                // Expected Output:
                //  Tadpole  400,  Spiral
                //  Pinwheel  25,  Spiral
                //  Cartwheel, 500,  Lenticular
                //  Small Magellanic Cloud .2,  Irregular
                //  Andromeda  3,  Spiral
                //  Maffei 1,  11,  Elliptical
            }
        }
    
        public class Galaxy
        {
            public string Name { get; set; }
    
            public double MegaLightYears { get; set; }
            public object GalaxyType { get; set; }
    
        }
    
        public class GType
        {
            public GType(char type)
            {
                switch(type)
                {
                    case 'S':
                        MyGType = Type.Spiral;
                        break;
                    case 'E':
                        MyGType = Type.Elliptical;
                        break;
                    case 'l':
                        MyGType = Type.Irregular;
                        break;
                    case 'L':
                        MyGType = Type.Lenticular;
                        break;
                    default:
                        break;
                }
            }
            public object MyGType { get; set; }
            private enum Type { Spiral, Elliptical, Irregular, Lenticular}
        }
    }
    

    Nossa intenção para este código é exibir o nome da galáxia, a distância até a galáxia e o tipo de galáxia em uma lista. Para depurar, é importante entender a intenção do código. Aqui está o formato de uma linha da lista que queremos mostrar na saída:

    nome de galáxia, distância, tipo de galáxia.

Executar o aplicativo

Pressione F5 ou o botão Iniciar Depuração, ícone que mostra o botão Iniciar Depuração. na Barra de Ferramentas de Depuração, localizada acima do editor de código.

A aplicação inicia e não há exceções mostradas pelo depurador. No entanto, a saída que você vê na janela do console não é o esperado. Aqui está a saída esperada:

Tadpole  400,  Spiral
Pinwheel  25,  Spiral
Cartwheel, 500,  Lenticular
Small Magellanic Cloud .2,  Irregular
Andromeda  3,  Spiral
Maffei 1,  Elliptical

Mas, em vez, vês este resultado:

Tadpole  400,  ConsoleApp_FirstApp.GType
Pinwheel  25,  ConsoleApp_FirstApp.GType
Cartwheel, 500,  ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2,  ConsoleApp_FirstApp.GType
Andromeda  3,  ConsoleApp_FirstApp.GType
Maffei 1, 11,  ConsoleApp_FirstApp.GType

Olhando para a saída e para o nosso código, sabemos que GType é o nome da classe que armazena o tipo de galáxia. Estamos tentando mostrar o tipo de galáxia real (como "Espiral"), não o nome da classe!

Depurar o aplicativo

  1. Com o aplicativo ainda em execução, insira um ponto de interrupção.

    No loop de foreach, clique com o botão direito do mouse ao lado do método Console.WriteLine para abrir o menu de contexto e selecione Ponto de interrupção>Inserir Ponto de Interrupção no menu flutuante.

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
    }
    

    Quando você define o ponto de interrupção, um ponto vermelho aparece na margem esquerda.

    À medida que você vê um problema na saída, você começa a depuração observando o código anterior que define a saída no depurador.

  2. Selecione o ícone Reiniciarque mostra o botão RestartApp na barra de ferramentas de depuração. botão na barra de ferramentas de depuração (Ctrl + Shift + F5).

    O aplicativo pausa no ponto de interrupção que você definiu. O realce amarelo indica onde o depurador está pausado (a linha amarela do código ainda não foi executada).

  3. Passe o cursor sobre a variável GalaxyType, à direita, e, em seguida, à esquerda do ícone da chave inglesa, expanda theGalaxy.GalaxyType. Você vê que GalaxyType contém uma propriedade MyGTypee o valor da propriedade está definido como Spiral.

    Captura de tela do depurador do Visual Studio com uma linha de código em amarelo e um menu aberto abaixo da propriedade Galaxy GalaxyType.

    "Espiral" é realmente o valor correto que você esperava imprimir no console! Portanto, é um bom começo que você possa acessar o valor nesse código enquanto executa o aplicativo. Nesse cenário, estamos usando a API incorreta. Vamos ver se você pode corrigir isso enquanto executa o código no depurador.

  4. No mesmo código, enquanto ainda estás a depurar, coloca o cursor no final do theGalaxy.GalaxyType e altera-o para theGalaxy.GalaxyType.MyGType. Embora você possa fazer a edição, o editor de código mostra um erro (linha ondulada vermelha). (No Visual Basic, o erro não é mostrado e esta seção de código funciona.)

  5. Pressione F11 (Debug>Step Into ou o botão Step Into na Barra de Ferramentas de Depuração) para executar a linha de código atual.

    F11 avança o depurador (e executa o código) uma instrução de cada vez. F10 (Step Over) é um comando semelhante, e ambos são úteis ao aprender a usar o depurador.

    Quando se tenta avançar o depurador, a janela de diálogo do Hot Reload aparece, indicando que as edições não podem ser compiladas.

    Captura de tela do depurador do Visual Studio com uma linha de código realçada em vermelho e uma caixa de mensagem com a opção Editar selecionada.

    A caixa de diálogo Editar e Continuar é exibida, indicando que as edições não podem ser compiladas.

    Captura de tela do depurador do Visual Studio com uma linha de código realçada em vermelho e uma caixa de mensagem com a opção Editar selecionada.

    Observação

    Para depurar o código de exemplo do Visual Basic, ignore as próximas etapas até ser instruído a clicar no ícone Reiniciarmostrando o botão Reiniciar aplicativo na barra de ferramentas Depurar. botão.

  6. Selecione Editar na Hot Reload ou Editar e Continuar na caixa de mensagem. Você vê uma mensagem de erro agora na janela Lista de Erros. O erro indica que o 'object' não contém uma definição para MyGType.

    Captura de tela do depurador do Visual Studio com uma linha de código realçada em vermelho e uma janela Lista de Erros com dois erros listados.

    Apesar de definirmos cada galáxia com um objeto do tipo GType (que tem a propriedade MyGType), o depurador não reconhece o objeto theGalaxy como um objeto do tipo GType. O que é que se passa? Você quer examinar qualquer código que define o tipo de galáxia. Quando fazes isso, vês que a classe GType definitivamente tem uma propriedade de MyGType, mas algo não está certo. A mensagem de erro sobre object acaba por ser a pista; Para o intérprete de linguagem, o tipo parece ser um objeto do tipo object em vez de um objeto do tipo GType.

  7. Olhando através do seu código relacionado com a definição do tipo de galáxia, você encontra a propriedade GalaxyType da classe Galaxy é especificada como object em vez de GType.

    public object GalaxyType { get; set; }
    
  8. Altere o código anterior da seguinte maneira:

    public GType GalaxyType { get; set; }
    
  9. Selecione o ícone Reiniciarque mostra o botão de reiniciar aplicação na barra de ferramentas de depuração. botão na barra de ferramentas de depuração (Ctrl + Shift + F5) para recompilar o código e reiniciar.

    Agora, quando o depurador faz uma pausa no Console.WriteLine, você pode passar o mouse sobre theGalaxy.GalaxyType.MyGTypee ver se o valor está definido corretamente.

  10. Remova o ponto de interrupção clicando no círculo do ponto de interrupção na margem esquerda (ou clique com o botão direito do mouse e escolha Ponto de interrupção>Excluir ponto de interrupção) e, em seguida, pressione F5 para continuar.

    O aplicativo é executado e exibe a saída. Está parecendo bom, mas você percebe uma coisa. Você esperava que a galáxia Pequena Nuvem de Magalhães aparecesse como uma galáxia irregular na saída do console, mas ela não mostra nenhum tipo de galáxia.

    Tadpole  400,  Spiral
    Pinwheel  25,  Spiral
    Cartwheel, 500,  Lenticular
    Small Magellanic Cloud .2,
    Andromeda  3,  Spiral
    Maffei 1,  Elliptical
    
  11. Defina um ponto de interrupção nessa linha de código antes da instrução switch (antes da instrução Select no Visual Basic).

    public GType(char type)
    

    Este código é onde o tipo de galáxia está definido, por isso queremos dar uma olhada mais de perto.

  12. Selecione o ícone Reiniciarque mostra o botão de reiniciar aplicativo na barra de ferramentas de depuração. botão na barra de ferramentas de depuração (Ctrl + Shift + F5) para reiniciar.

    O depurador pausa na linha de código onde você define o ponto de interrupção.

  13. Passe o cursor sobre a variável type. Você verá um valor de S (seguindo o código do caractere). Está interessado num valor de I, já que sabe que esse é um tipo de galáxia irregular.

  14. Pressione F5 e passe o mouse sobre a variável type novamente. Repita esta etapa até ver um valor de I na variável type.

    Captura de tela do depurador do Visual Studio com uma linha de código em amarelo e uma janela com o valor da variável de tipo 73 I.

  15. Agora, pressione F11 (Debug>Step Into).

  16. Pressione F11 até parar na linha de código na instrução switch para obter um valor de 'I' (instruçãoSelect para Visual Basic). Aqui, você vê um problema claro resultante de um erro de digitação. Você esperava que o código avançasse para onde ele define MyGType como um tipo de galáxia irregular, mas o depurador ignora esse código completamente e pausa na seção default da instrução switch (instruçãoElse no Visual Basic).

    Captura de tela mostrando o erro de digitação.

    Olhando para o código, você vê um erro de digitação na instrução case 'l'. Deve ser case 'I'.

  17. Selecione o código case 'l' e substitua-o por case 'I'.

  18. Remova o ponto de interrupção e, em seguida, selecione o botão Reiniciar para reiniciar a aplicação.

    Os bugs foram corrigidos agora e você vê a saída que você espera!

    Pressione qualquer tecla para concluir o aplicativo.

Resumo

Quando vir um problema, use o depurador e os comandos de etapa como F10 e F11 para localizar a região do código com o problema.

Observação

Se for difícil identificar a região do código onde o problema ocorre, defina um ponto de interrupção no código que é executado antes do problema e, em seguida, utilize comandos de execução passo a passo até que o problema se manifeste. Você também pode usar pontos de rastreamento para registrar mensagens na janela de saída do . Ao olhar para as mensagens registradas (e perceber quais mensagens ainda não foram registradas!), muitas vezes você pode isolar a região do código com o problema. Poderá ter de repetir este processo várias vezes para o restringir.

Quando você encontrar a região de código com o problema, use o depurador para investigar. Para encontrar a causa de um problema, inspecione o código do problema enquanto executa seu aplicativo no depurador:

  • Inspecione as variáveis e verifique se elas contêm o tipo de valores que devem conter. Se você encontrar um valor incorreto, descubra onde o valor incorreto foi definido (para encontrar onde o valor foi definido, talvez seja necessário reiniciar o depurador, examinar a pilha de chamadas ou ambos).

  • Verifique se seu aplicativo está executando o código esperado. (Por exemplo, no aplicativo de exemplo, esperávamos que o código da instrução switch definisse o tipo de galáxia como Irregular, mas o aplicativo ignorou o código devido ao erro de digitação.)

Dica

Você usa um depurador para ajudá-lo a encontrar erros. Uma ferramenta de depuração pode encontrar bugs para você apenas se souber a intenção do seu código. Uma ferramenta só pode saber a intenção do seu código se você, o desenvolvedor, expressar essa intenção. Escrever testes de unidade é como você faz isso.

Próximos passos

Neste artigo, aprendeste alguns conceitos gerais de depuração. Em seguida, você pode começar a aprender mais sobre o depurador.