Como um engenheiro de controle de qualidade salvou um dia inteiro vinculando Testes automáticos no Visual Studio e Test IT

As modernas ferramentas de trabalho do desenvolvedor são uma dúzia de aplicativos diferentes: um IDE, um sistema de teste, várias estruturas, sistemas de controle de versão e de contêiner, aplicativos de escritório e muito mais.

E, muitas vezes, sem perceber, passamos um tempo precioso transferindo dados de um sistema em funcionamento para outro. Mas por que não adotamos a otimização do fluxo de trabalho, mesmo em pequenas coisas? Cinco minutos, multiplicados por 5 vezes por dia, fornecerão um total de mais de um dia útil por mês, tempo que pode ser gasto muito mais útil do que a realização de trabalhos de rotina. Então, chegamos à criação de uma extensão para o Visual Studio, que nos permite automatizar o processo de criação de testes automáticos em nosso sistema de TI de teste.

Continuando a história dos webhookse como eles ajudam a conectar muitos serviços no trabalho, apresentamos a nossa história sobre a criação de uma extensão para o nosso IDE de trabalho - Visual Studio. Bem-vindo ao gato!

Este artigo é uma postagem de convidado da equipe do Test IT.



O chatbot discutido no artigo anterior é, obviamente, bom, mas até agora serve apenas para obter informações sobre o status atual dos autotestes. E se configurarmos uma integração mais rigorosa com o sistema de TI de teste, poderemos expandir a lista de testes do projeto atual no portal automaticamente, sem a necessidade de adicioná-los manualmente.

Anteriormente, para isso, usamos uma biblioteca implantada às pressas e um aplicativo de console que, na inicialização, analisou a solução atual, encontrou um projeto de teste, extraiu uma lista de autotestes de seu assembly e os enviou para nossa API. Parece que você pode deixar assim, porque a solução funciona. Mas procrastinar constantemente um projeto inteiro (mesmo que seja um método que chama de forma assíncrona a biblioteca) é muito difícil, e as dependências eternas dos projetos entre si também não são um sinal de bom gosto.

Chegamos à criação da extensão para o Visual Studio e agora contaremos um pouco sobre como a fizemos.

Lado técnico


Naturalmente, desenvolveremos a extensão no Visual Studio. Afinal, ninguém sabe sobre o IDE tanto quanto o próprio IDE. Primeiro, verifique se o Visual Studio possui todos os componentes necessários para criar extensões. Encontramos e iniciamos o Instalador do Visual Studio e verificamos o módulo "Desenvolvimento de extensões do Visual Studio":



Uma verificação é suficiente para instalarmos todas as bibliotecas necessárias para o trabalho. As informações sobre a instalação para o desenvolvimento de extensões do Visual Studio devem ser aproximadamente a seguinte situação: A



parte preparatória acabou, podemos continuar criando um novo projeto e mergulhar na arquitetura e estrutura do modelo de extensão.

Expandiremos a nova extensão, localizando a lista de soluções disponíveis usando a frase "VSIX" e escolhendo o projeto VSIX (C #, é claro):



Após a implantação, a arquitetura simples do modelo de extensão é vista à primeira vista:



neste exemplo, source.extension.vsixmanifest é um manifesto comum que descreve as propriedades básicas da extensão, como nome do produto, autor, versão, descrição, ícone da extensão, versão de destino do IDE. e muitos outros. A propósito, são essas propriedades exibidas no repositório de extensões e no instalador de extensões do Visual Studio.

O VSIXProject3Package.cs (máscara: {ProjectName} Package.cs), por sua vez, é uma classe inicializadora que registra todos os comandos e esquemas de recursos disponíveis. Vamos conhecer as equipes agora.

Vamos criar uma nova equipe que abre uma janela do WPF com parâmetros de extensão: precisamos armazenar dados sobre o projeto de destino, o local e o nome de seu assembly, a conexão com o servidor e outras informações em algum lugar.

Estamos procurando um novo elemento, chamado Comando bastante lógico .



Muitos podem se perguntar: por que usamos Command quando a Janela de Ferramentas Assíncronas e a Janela de Ferramentas são adequadas para a descrição da tarefa, de acordo com o nome? Tudo é bem simples: ao criar esses dois elementos, implantaremos um arquivo de marcação no xaml, um arquivo cs com o mesmo nome e também um comando. Tudo ficaria bem, como precisamos, mas nesse caso, a Janela da Ferramenta (não importa se é assíncrona) implanta um modelo de janela que se integra ao Visual Studio. Na saída, obtemos uma das janelas, que é expandida por padrão em vez da janela Debug. Claro, tudo isso é personalizável, mas precisamos de uma janela de terceiros. É por isso que não usamos a Janela de Ferramentas, mas adicionamos uma janela WPF comum.

Penso que os detalhes da criação de uma nova janela com elementos padrão podem ser omitidos, pois são chatos, desinteressantes e pouco relacionados ao título do artigo. A única recomendação que você pode deixar aqui: O Visual Studio ao adicionar um novo elemento não mostrará a janela WPF na lista de opções; portanto, a opção mais rápida e fácil é criar essa janela separadamente do projeto de extensão e depois transferi-la para o projeto atual (não esqueça de corrigir o espaço nomes).



Então, depois de criar uma nova equipe, que chamamos de OpenSettingsCommand, a lendária geração de código do estúdio cria uma classe de equipe e um arquivo no formato vsct que armazena a marcação de nossa extensão e o mapeamento de comandos e os botões que as chamam. É altamente desejável reescrever a marcação em sua própria implementação: criada automaticamente, ele colocará seus elementos no menu "Extensões". Nesse caso, reescrevemos essa marcação criando um grupo de duas equipes e colocando-a diretamente na barra de ferramentas. Um exemplo de comando e marcação pode ser encontrado em nosso repositório .

Na classe criada, podemos observar o método Execute, com o qual tudo começa quando esse comando é chamado. Na verdade, é aqui que vamos registrar a inicialização da nova janela do WPF.

Envdte


E abordamos sem problemas o uso do SDK do Visual Studio, a biblioteca EnvDTE. Essa biblioteca COM permite que trabalhemos com objetos e elementos do Visual Studio: obtenha uma lista de soluções e projetos ativos, trabalhe com destaque de sintaxe, janelas ativas, leia o código do projeto e muito mais. De fato, se você se aprofundar na documentação desta biblioteca, poderá encontrar muitas funções úteis. Neste exemplo, usamos-o precisamente para obter uma lista de projetos em uma solução ativa.

Apesar da pequena base de código livre, precisamos apenas de algumas linhas de código para obter uma lista de projetos na solução ativa:

ThreadHelper.ThrowIfNotOnUIThread();
var activeVS = (DTE)Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.GetService(typeof(DTE))
 ?? throw new InvalidOperationException("DTE not found");
var activeProjects = new List<Project>();
activeProjects.AddRange(activeVS.Solution.Projects.Cast<Project>());
//  , activeProjects         

Com tanta facilidade e naturalidade, podemos coletar informações detalhadas sobre todos os projetos ativos.

Pegue nesta lista os nomes do projeto (propriedade Nome) e o caminho para os arquivos csproj (de repente, Nome Completo): basta pedir ao usuário o projeto desejado da lista de possíveis e mapeá-lo para o diretório para pesquisar assemblies.

A próxima etapa é conectar a biblioteca, cujas tarefas são analisar a montagem, coletar autotestes e publicá-las no portal Test IT. Omitiremos os detalhes da criação da biblioteca, mas forneceremos uma classe interessante que pode obter a lista de autotestes do assembly carregado:

public class AutotestsService
    {
        public IList<AutotestModel> GetAutotestsFromAssembly<TTestClassAttribute, TTestMethodAttribute>(Assembly assembly, Guid projectId, string repositoryLink)
            where TTestClassAttribute : Attribute
            where TTestMethodAttribute : Attribute
        {
            MethodInfo[] testMethods = GetAutotestFromAssembly<TTestClassAttribute, TTestMethodAttribute>(assembly);

            List<AutotestModel> allModels = new List<AutotestModel>();
            foreach (MethodInfo method in testMethods)
            {
                AutotestModel autotest = new AutotestModel()
                {
                    ExternalId = method.Name,
                    LinkToRepository = repositoryLink,
                    ProjectId = projectId,
                    Name = GetAutotestName(method.Name),
                    Classname = method.DeclaringType.Name,
                    Namespace = GetAutotestNamespace(method)
                };

                allModels.Add(autotest);
            }

            return allModels;
        }

        private static MethodInfo[] GetAutotestFromAssembly<TTestClassAttribute, TTestMethodAttribute>(Assembly assembly)
            where TTestClassAttribute : Attribute
            where TTestMethodAttribute : Attribute
        {
            return assembly.GetTypes()
                .Where(c => c.IsDefined(typeof(TTestClassAttribute)))
                .SelectMany(t => t.GetMethods())
                .Where(m => m.IsDefined(typeof(TTestMethodAttribute)))
                .ToArray();
        }

        private string GetAutotestName(string autotestExternalId)
        {
            StringBuilder autotestName = new StringBuilder();

            for (int i = 0; i < autotestExternalId.Length; i++)
            {
                if (char.IsUpper(autotestExternalId[i]) && i != 0)
                    autotestName.Append(' ');
                autotestName.Append(autotestExternalId[i]);
            }

            return autotestName.ToString();
        }

        private string GetAutotestNamespace(MethodInfo testMethod)
        {
            return testMethod.DeclaringType.FullName
                .Replace($".{testMethod.DeclaringType.Name}", string.Empty);
        }
    }

Todo o código fonte da biblioteca sempre pode ser visualizado em nosso repositório .

Então, de volta à extensão. Para iniciar a lógica da nossa biblioteca, você precisa adicionar um novo comando, no método Execute do qual escrevemos a chamada da biblioteca, passando os atributos das classes e métodos de teste, bem como os parâmetros de extensão salvos:

var settings = Properties.Settings.Default;
var executor = new LinkExecutor();
await executor.Execute<TestClassAttribute, TestMethodAttribute>(
    settings.Domain,
    settings.SecretKey,
    settings.ProjectNameInTestIT,
    settings.RepositoryLink ?? string.Empty,
    settings.AssemblyPath,
    Logger);

Nota importante: pulamos o criador de logs na biblioteca para poder gravar informações técnicas diretamente na janela de saída de mensagens do Visual Studio. A biblioteca não deve estar vinculada apenas a esse IDE; é importante deixar a oportunidade de usá-lo em qualquer situação.

resultados


Como resultado, após o desenvolvimento, obtivemos algo como esta extensão:



. , Visual Studio, , Visual Studio Visual Studio Visual Studio Visual Studio. , .



Vamos abrir um exemplo de solução que contém um projeto com testes de unidade e testar nossa extensão. Ao carregar um projeto, podemos notar imediatamente um novo botão no painel:



Pegue imediatamente a chave secreta da API da sua conta pessoal e prepare um novo projeto em nossa plataforma:





Em seguida, voltemos à extensão. Vamos abrir nossa janela com os parâmetros de extensão e preencher os campos:



passamos a lista de projetos atuais para o designer de janelas, gentilmente fornecido pela biblioteca SDK do Visual Studio, e carregamos as opções “Project dll” após selecionar o projeto: o serviço procurou todos os arquivos dll na montagem do projeto UnitTestProject ”E nos mostrou possíveis opções de biblioteca. Salvamos as configurações e executamos a principal funcionalidade de nossa extensão.

Na janela de saída, após alguns segundos, vemos o seguinte:



Quem se importa com a forma como produzimos as mensagens - o código fonte do criador de logs pode ser encontrado aqui .

No nosso exemplo, houve 3 testes de Unidade e 3 testes de integração. Parece a verdade. Verifique se existe um portal:



Conclusão


Hoje, examinamos o básico da criação de extensões para o Visual Studio usando o exemplo de uma extensão para publicar uma lista de autotestes na plataforma Test IT. As opções de extensão são limitadas apenas pela sua imaginação: você pode implementar um bate-papo com uma equipe, criar notificações em caso de falha do projeto em sua filial, até adicionar um botão de pedido de pizza ao escritório , como em nossas fantasias sobre o Bot Framework .

Sonhe, crie, economize tempo e permaneça sempre especialista em criação!

Sobre o autor



Mikhail Pirogovsky é desenvolvedor .NET. O material foi escrito com a equipe de TI de teste. Em nosso grupo no Facebook, falamos sobre trabalhar em controle de qualidade, testes, ferramentas e muito mais.

All Articles