Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Sem falhas, o código que escrevemos como desenvolvedores de software nem sempre faz o que esperávamos que ele fizesse. Às vezes faz algo completamente diferente! Quando o inesperado acontece, a próxima tarefa é descobrir o porquê e, embora possamos ficar tentados a continuar 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 possa magicamente revelar todos os problemas ou "bugs" em nosso código. Depuração significa executar o código passo a passo em uma ferramenta de depuração, como o Visual Studio, para localizar o ponto exato em que você cometeu um erro de programação. Em seguida, você entende quais correções você precisa fazer em seu código e 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 efetivamente também é uma habilidade que leva tempo e prática para aprender, mas é, em última análise, uma tarefa fundamental para cada desenvolvedor de software. Neste artigo, introduziremos os princípios fundamentais da depuração e forneceremos dicas para você começar.
Esclarecer o problema fazendo-se as perguntas certas
Ajuda a esclarecer o problema que você encontrou antes de tentar corrigi-lo. Esperamos que você já se deparou com um problema em seu código, caso contrário, você não estaria aqui tentando descobrir como depurá-lo! Portanto, antes de iniciar a depuração, verifique se você identificou o problema que está tentando 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, isso pode ser uma coisa boa! Uma exceção é um evento inesperado encontrado ao executar o código, normalmente um erro de algum tipo. Uma ferramenta de depuração pode levá-lo ao local exato em seu código em que 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 em seu código? Por exemplo, se o código exibir algum texto, mas o texto estiver incorreto, você saberá que os dados são incorretos 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.
Examinar 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á analisando diretamente a causa do problema em um depurador. Você pode ter uma longa lista de possíveis suposições! Aqui estão algumas perguntas para se fazer para desafiar suas suposições.
Você está usando a API certa (ou seja, o objeto certo, a função, o método ou a propriedade)? Uma API que você está usando pode não fazer o que você acha que faz. (Depois de analisar a chamada à API no depurador, corrigi-la pode exigir uma consulta à documentação para ajudar a identificar a API correta.)
Você está usando uma API corretamente? Talvez você tenha usado a API certa, mas não a usou da maneira certa.
Seu código contém erros 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 linguagens que não exigem que variáveis sejam declaradas antes de serem usadas.
Você fez uma alteração no código e assumiu que não está relacionado ao problema que você está vendo?
Você esperava que um objeto ou variável contivesse um determinado valor (ou um determinado tipo de valor) diferente do que realmente aconteceu?
Você sabe a intenção do código? Geralmente, é mais difícil depurar o código de outra pessoa. Se não for seu código, você pode precisar gastar tempo aprendendo exatamente o que o código faz antes de poder depurá-lo de forma eficaz.
Dica
Ao escrever código, comece pequeno e comece com o código que funciona! (Um bom código de exemplo é útil aqui.) Às vezes, é mais fácil corrigir um grande ou complicado conjunto 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 para 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 seu código no modo de depuração para descobrir onde o problema ocorreu
Quando você normalmente executa um aplicativo, você vê erros e resultados incorretos somente após a execução do código. Um programa também pode terminar inesperadamente sem dizer por quê.
Quando você executa um aplicativo em um depurador, também chamado modo de depuração, o depurador monitora ativamente tudo o que está acontecendo enquanto o programa é executado. Isso também permite pausar o aplicativo a qualquer momento para examinar seu estado e percorrer o código linha por linha para observar todos os detalhes à medida que acontecem.
No Visual Studio, você entra no modo de depuração usando F5 (ou o comando de menu Depuração>Iniciar Depuração ou o botão Iniciar Depuração na Barra de Ferramentas de Depuração). Se ocorrerem exceções, o Auxiliar de Exceção do Visual Studio levará você ao ponto exato em que a exceção ocorreu e fornecerá outras informações úteis. Para obter mais informações de como tratar exceções no código, confira Técnicas e ferramentas de depuração.
Se você não tiver uma exceção, provavelmente terá uma boa ideia de onde procurar o problema em seu código. É nessa etapa que você usa os pontos de interrupção com o depurador para ter uma oportunidade de examinar o código mais cuidadosamente. Pontos de interrupção são o recurso mais básico e essencial da depuração confiável. Um ponto de interrupção indica onde o Visual Studio deve pausar o código em execução para que você possa dar uma olhada nos valores das variáveis ou no 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 em uma linha e pressione F9.
Para ajudar a ilustrar esses conceitos, levamos você por um código de exemplo que já tem vários bugs. Estamos usando C#, mas os recursos de depuração se aplicam a Visual Basic, C++, JavaScript, Python e outros idiomas com suporte. 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.
Você precisa ter o Visual Studio instalado e a carga de trabalho de Desenvolvimento para desktop com .NET instalada.
Se você ainda não instalou o Visual Studio, acesse a página 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 Visual Studio Installer é iniciado. Escolha a carga de trabalho Desenvolvimento para desktop com .NET e, em seguida, selecione Modificar.
Abra o Visual Studio.
Na janela inicial, escolha Criar um novo projeto. Digite console na caixa de pesquisa, selecione C# ou do Visual Basic como o idioma e, em seguida, escolha Aplicativo de Console para .NET. Escolha Avançar. Digite ConsoleApp_FirstApp como o nome do projeto e selecione Próximo.
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 entre a estrutura de destino recomendada ou .NET 8 e depois escolha Criar.
Caso não veja o modelo de projeto Aplicativo de Console para o .NET, acesse Ferramentas>Obter Ferramentas e Recursos e o Visual Studio Installer será aberto. Escolha a carga de trabalho Desenvolvimento para desktop com .NET e, em seguida, selecione Modificar.
O Visual Studio cria o projeto de console, que aparece no Gerenciador de Soluções no painel direito.
Em Program.cs (ou Program.vb), substitua todo o código padrão pelo código a seguir. (Selecione a guia de idioma correta primeiro, 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 tudo em uma lista. Para depurar, é importante entender a intenção do código. Aqui está o formato de uma linha da lista que desejamos mostrar na saída:
Nome da galáxia , distância , tipo de galáxia .
Executar o aplicativo
Pressione F5 ou o botão Iniciar Depuração na Barra de Ferramentas de Depuração, localizada acima do editor de código.
O aplicativo é iniciado e não há exceções mostradas pelo depurador. No entanto, a saída que você vê na janela do console não é o que você espera. Esta é 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 disso, você verá esta saída:
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 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
Com o aplicativo ainda em execução, insira um ponto de interrupção.
No loop
foreach
, clique com o botão direito do mouse ao lado do métodoConsole.WriteLine
para mostrar o menu de contexto e selecione Ponto de Interrupção>Inserir Ponto de Interrupção no menu que aparece.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.
Ao ver um problema na saída, você inicia a depuração examinando o código anterior que define a saída no depurador.
Selecione o botão Reiniciar
na Barra de Ferramentas de Depuração (Ctrl + Shift + F5).
O aplicativo pausa no ponto de interrupção definido. O realce amarelo indica onde o depurador está em pausa (a linha amarela de código ainda não foi executada).
Passe o mouse sobre a variável
GalaxyType
à direita e, em seguida, à esquerda do ícone de chave inglesa, expandatheGalaxy.GalaxyType
. Você verá queGalaxyType
contém uma propriedadeMyGType
e o valor da propriedade é definido comoSpiral
."Espiral" é, na verdade, o valor correto que você esperava imprimir no console! É um bom começo que você consiga acessar o valor nesse código enquanto o aplicativo está em execução. Nesse cenário, estamos usando a API incorreta. Vamos ver se você pode corrigir isso durante a execução do código no depurador.
No mesmo código, ainda durante a depuração, coloque o cursor no final de
theGalaxy.GalaxyType
e altere-o paratheGalaxy.GalaxyType.MyGType
. Embora você possa fazer a edição, o editor de código mostra um erro (pequena linha vermelha). (No Visual Basic, o erro não é mostrado e esta seção do código funciona.)Pressione F11 (Depurar>Intervir ou o botão Intervir 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 por vez. F10 (Step Over) é um comando semelhante e ambos são úteis ao aprender a usar o depurador.
Quando você tenta avançar o depurador, a caixa de diálogo Recarga Dinâmica é exibida, indicando que as edições não podem ser compiladas.
A caixa de diálogo Editar e Continuar é exibida, indicando que as edições não podem ser compiladas.
Nota
Para depurar o código de exemplo do Visual Basic, ignore as próximas etapas até que você seja instruído a clicar no botão Reiniciar
.
Selecione Editar na caixa de mensagem Recarga Dinâmica ou Editar e Continuar. 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 paraMyGType
.Embora definimos cada galáxia com um objeto do tipo
GType
(que tem a propriedadeMyGType
), o depurador não reconhece o objetotheGalaxy
como um objeto do tipoGType
. O que está acontecendo? Você deseja analisar qualquer código que defina o tipo de galáxia. Quando você fizer isso, verá que a classeGType
definitivamente tem uma propriedade deMyGType
, mas algo não está certo. A mensagem de erro sobreobject
acaba por ser a pista; para o interpretador de linguagem, o tipo parece ser um objeto do tipoobject
em vez de um objeto do tipoGType
.Examinando seu código relacionado à configuração do tipo de galáxia, você encontra que a propriedade
GalaxyType
da classeGalaxy
está especificada comoobject
em vez deGType
.public object GalaxyType { get; set; }
Altere o código anterior da seguinte maneira:
public GType GalaxyType { get; set; }
Selecione o ícone Reiniciar
botão na barra de ferramentas de Depuração (Ctrl + Shift + F5) para recompilar o código e reiniciar.
Agora, quando o depurador pausa em
Console.WriteLine
, você pode passar o mouse sobretheGalaxy.GalaxyType.MyGType
e ver se o valor está definido corretamente.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 e selecione 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 nenhum tipo de galáxia é mostrado.
Tadpole 400, Spiral Pinwheel 25, Spiral Cartwheel, 500, Lenticular Small Magellanic Cloud .2, Andromeda 3, Spiral Maffei 1, Elliptical
Defina um ponto de interrupção nessa linha de código antes da instrução
switch
(antes da instruçãoSelect
no Visual Basic).public GType(char type)
Este código é onde o tipo de galáxia está definido, então queremos dar uma olhada mais de perto nele.
Selecione o botão Reiniciar
na Barra de Ferramentas de Depuração (Ctrl + Shift + F5) para reiniciar.
O depurador pausa na linha de código em que você define o ponto de interrupção.
Passe o mouse sobre a variável
type
. Você verá um valor deS
(seguindo o código de caractere). Você está interessado em um valor deI
, uma vez que você sabe que é um tipo de galáxia Irregular.Pressione F5 e passe o mouse sobre a variável
type
novamente. Repita esta etapa até ver um valor deI
na variáveltype
.Agora, pressione F11 (Depurar>Intervir).
Pressione F11 até parar na linha de código na instrução
switch
para obter um valor "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 defineMyGType
como um tipo de galáxia Irregular, mas o depurador ignora completamente esse código e pausa na seçãodefault
da instruçãoswitch
(instruçãoElse
no Visual Basic).Olhando para o código, você verá um erro de digitação na instrução
case 'l'
. Deve sercase 'I'
.Selecione o código de
case 'l'
e substitua-o porcase 'I'
.Remova o ponto de interrupção e selecione o botão Reiniciar para reiniciar o aplicativo.
Os bugs já foram corrigidos e você pode ver a saída esperada!
Pressione qualquer tecla para concluir o aplicativo.
Resumo
Quando você vir um problema, use o depurador e os comandos de etapa como F10 e F11 para localizar a região de código com o problema.
Nota
Se for difícil identificar a região do código em que o problema ocorre, defina um ponto de interrupção no código executado antes que o problema ocorra e use comandos de etapa até ver o manifesto do problema. Também é possível usar tracepoints para registrar as mensagens na janela de Saída. Examinando mensagens registradas (e percebendo quais mensagens ainda não foram registradas!), você pode isolar frequentemente a região do código com o problema. Talvez seja necessário repetir esse processo várias vezes para reduzi-lo.
Quando encontrar a parte do código que apresenta o problema, use o depurador para investigar. Para encontrar a causa de um problema, inspecione o código do problema ao executar 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 atribuído (para descobrir onde o valor foi atribuído, talvez seja necessário reiniciar o depurador, examinar a pilha de chamadas ou ambos).
Verifique se o 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 ajudar você a encontrar erros. Uma ferramenta de depuração poderá localizar bugs para você somente se conhecer a intenção do seu código. Uma ferramenta só poderá saber a intenção do seu código se você, o desenvolvedor, expressar essa intenção. Gravar testes de unidade é como se faz isso.
Próximas etapas
Neste artigo, você aprendeu alguns conceitos gerais de depuração. Em seguida, você pode começar a aprender mais sobre o depurador.