Problemas com o atributo DeploymentItem

94

No momento, estou mantendo um sistema "antigo" escrito em C # .net, removendo alguns recursos obsoletos e fazendo algumas refatorações. Graças a Deus, o cara anterior escreveu alguns testes de unidade (MSTests). Estou bastante confortável com os testes JUnit, mas ainda não fiz muito com os MSTests.

Os métodos de teste têm um DeploymentItematributo, especificando um arquivo de texto que é analisado pelo método de lógica de negócios que está sendo testado e um segundo DeploymentItemonde apenas um caminho foi especificado contendo um monte de arquivos TIF que também devem ser implantados.

[TestMethod()]
[DeploymentItem(@"files\valid\valid_entries.txt")]
[DeploymentItem(@"files\tif\")]
public void ExistsTifTest()
{
   ...
}

Os testes funcionaram antes, mas agora eu tive que alterar os nomes dos arquivos TIF contidos no diretório \ files \ tif. De acordo com uma regra, os nomes de arquivo TIF devem corresponder a um determinado padrão que também é verificado pelo ExistsTifTest()método. Agora tive que mudar os nomes dos arquivos para adaptá-los aos novos requisitos e de repente os arquivos TIF não estão mais sendo implantados como antes.

Alguém pode me dar uma dica de por que isso acontece ou qual pode ser a causa? A mesma coisa acontece também se eu adicionar um novo arquivo de texto dizer "my2ndTest.txt" ao lado de "valid_entries.txt" no diretório \ files \ valid \ com o atributo DeploymentItem de acordo no método de teste. O arquivo não é implantado?

Consegui as imagens agora implantadas definindo o caminho de implantação diretamente no testrunconfig, mas gostaria de entender por que essas coisas acontecem ou por que, por exemplo, meu novo arquivo "my2ndTest.txt" não é implantado enquanto os outros o fazem.

Juri
fonte
2
Uma grande pegadinha aqui é perceber que todos os itens especificados no DeploymentItemAttribute serão copiados para o local de onde seus assemblies de teste são executados. Em outras palavras, se você esperava que isso preservasse sua estrutura de diretórios, você não teria sorte. Se você precisar copiá-lo para um diretório específico, use a versão de dois parâmetros DeploymentItem (source, outputDir). Para sua informação - você pode ir à velha escola para descobrir onde os arquivos são executados para o MsTest inserindo um System.Console.WriteLine (System.Environment.CurrentDirectory) em um de seus testes. NCrunch não teve esse problema!
CodeMonkeyKing 01 de

Respostas:

111

DeploymentItem é uma bagunça.

Cada arquivo em sua solução terá uma configuração "Copiar para pasta de saída" no VS.NET. Você precisa que seja "Copiar sempre" (ou similar) para colocar os arquivos na pasta de saída.

Verifique se você tem esse conjunto para os novos arquivos. Se você não tiver esse conjunto, os arquivos não serão copiados para a pasta de saída e não podem ser implantados da pasta de saída para a pasta onde o MSTest faz as coisas.

Pessoalmente, se eu tenho arquivos que preciso para meus testes de unidade, descobri que incorporar esses arquivos como recursos em um assembly, e fazer com que o assembly "descompacte" durante os testes é uma maneira mais previsível de fazer as coisas. YMMV.

Nota: esses comentários são baseados em minha experiência com o VS2010. Comentários à minha resposta sugerem que isso não é problema com o VS2012. Ainda mantenho comentários de que usar recursos integrados envolve menos "mágica" e, para mim, torna o estágio de "organizar" de meus testes de unidade muito mais explícito.

Martin Peck
fonte
3
Copiar para diretório de saída nunca afeta como o MSTest implanta arquivos. Esta resposta está incorreta.
kzu
19
No VS2010 Premium, fazer essa alteração (e nenhuma outra) causou a implantação do arquivo. Portanto, concluo com base na evidência real de que AFETA a implantação do MsTest.
JonStonecash,
1
Acordado. Eu vi essa única mudança virar o DeploymentItem de cabeça para baixo.
Martin Peck
2
Isso parece não ser mais necessário no VS2012. Meus itens de implantação estão sendo implantados com "Copiar para pasta de saída" definido como "Não copiar".
Mike de
29
É ótimo como o DeploymentItem não avisa quando não consegue copiar o único arquivo fornecido.
74

No VS2010, meu Local.testsettings tinha "Habilitar implantação" desmarcado e o atributo DeploymentItem não estava funcionando. Eu verifiquei e tudo funcionou bem. Eu espero que isso ajude!

Ivan Muzzolini
fonte
2
Eu tenho batido minha cabeça contra uma parede de tijolos há anos tentando fazer funcionar .... obrigado!
mat-mcloughlin
12
Acho que teria sido bom se a estrutura emitisse um aviso informando que os atributos DeploymentItem estão sendo ignorados se essa configuração for desativada. Também coloquei uma bela impressão côncava em minha mesa.
Alan McBee - MSFT
2
Observe que Local.testsettings está em Itens de solução
Matthew Lock,
Também tive que adicionar o diretório contendo os itens que eu queria implantar em Local.testsettings também: i.imgur.com/p1z3m9R.png
Matthew Lock,
Usar o VS2017 em 2018 marcando 'Ativar implantação' ainda é a solução para este problema. E, infelizmente, ainda agora avisando do Visual Studio. Então, obrigado por esta solução.
Don H
19

Eu também enfrentei problemas semelhantes, mas encontrei uma solução fácil de 3 etapas para isso:

Supondo que sua estrutura de pastas seja assim: SolutionFolder\ TestProjectFolder\ SubFolder\

  1. Vá para "Solutions Items / Local.testsettings"> "Deployment"> Marque "Enable Deployment"
  2. Se você estiver usando o VS2010, certifique-se de que todos os arquivos que deseja implantar tenham a propriedade "Copiar para a pasta de saída" definida como "Copiar sempre" ou "Copiar se mais recente"
  3. Atribua seu TestMethod com um dos seguintes:
    • [DeploymentItem(@"TestProjectFolder\SubFolder")]para implantar todo o conteúdo do <SubFolder>diretório Test Run
    • [DeploymentItem(@"TestProjectFolder\SubFolder", "TargetFolder")] para implantar todo o conteúdo do <SubFolder>que <TargetFolder>no diretório Test Run

Uma nota final sobre o MSTest (pelo menos para VS2010):

Se você quiser que o <TargetFolder>tenha o mesmo nome que o <SubFolder>, o uso [DeploymentItem(@"SubFolder", @"SubFolder")]falhará silenciosamente quando o runner do MSTest atingir um caso extremo bobo. É por isso que você deve prefixar o <SubFolder>com <TestProjectFolder>assim:[DeploymentItem(@"TestProjectFolder\SubFolder", @"SubFolder")]

Murari Kumar
fonte
A observação sobre a falha na nomenclatura da subpasta é uma joia.
RJ Lohan
1
VS 2015 parece um pouco diferente. Eu precisava remover a parte "TestPojectFolder" no Atributo DeploymentItem.
uli78
15

Para ajudar alguém mais: tentei todas as sugestões aqui e meu item de implantação ainda não estava sendo copiado.

O que eu tive que fazer ( como sugerido aqui ) foi adicionar um segundo parâmetro ao atributo DeploymentItem:

[DeploymentItem(@"UnitTestData\TestData.xml", "UnitTestData")]
Peter K.
fonte
10

Se você entrar em seu arquivo .testrunconfig e em implantação desmarcar "Ativar implantação", os testes serão executados em seu local normal e tudo funcionará como ao executar o aplicativo fora de um teste de unidade.

Josh Close
fonte
Tive alguns problemas com isso também. Como PM, não tenho acesso a todas as ferramentas utilizadas pelo dev. Neste caso, o ReSharper copiou o arquivo corretamente, enquanto o MSTest falhou em fazê-lo. -> Eu encontrei erros enquanto dev estava OK. Mude para 'Teste-> Editar configurações de teste -> Configurações locais -> Implementação' incluindo o arquivo em questão corrigido para o meu uso MSTest.
sonstabo de
9

Isso provavelmente não está relacionado ao seu problema exato, mas aqui estão algumas dicas que encontrei com o atributo [DeploymentItem].

  1. Copiar para o diretório de saída deve ser definido como Copiar sempre.

Ele não funciona quando utilizado com o atributo [TestInitialize]

[TestInitialize]
[DeploymentItem("test.xlsx")]
public void Setup()
{

Deve estar no seu [TestMethod], por exemplo

    [TestInitialize]
    public void Setup()
    {
        string spreadsheet = Path.GetFullPath("test.xlsx");
        Assert.IsTrue(File.Exists(spreadsheet));
        ...
    }

    [TestMethod]
    [DeploymentItem("test.xlsx")]
    public void ExcelQuestionParser_Reads_XmlElements()
    {
        ...
    }
Matt Frear
fonte
1
Esta é uma limitação extremamente irritante. Sinto que, em muitos casos, o tempo de implantação deve ser inicializar. E se todos os meus testes usarem os mesmos artefatos de suporte? Acho que devo copiar e colar decoradores em dezenas de métodos de teste. Ridículo.
Ryanman
5

Depois de tentar todas as outras sugestões listadas aqui, ainda não consegui descobrir o que estava acontecendo. Finalmente, descobri que não havia nenhum arquivo de configurações selecionado no menu Test / Test Settings, o que significava que a implantação não estava sendo habilitada. Cliquei no item de menu Testar / Testar configurações / Selecionar arquivo de configurações de teste, selecionei o arquivo Local.TestSettings e tudo funcionou.

Mike
fonte
4

Não tenho certeza se isso responde exatamente à pergunta, mas pode ajudar um pouco. Primeiro, descobri que a caixa "Habilitar implantação" deve ser marcada para que a implantação funcione. Em segundo lugar, o documento diz que o caminho de origem é "relativo ao caminho do projeto", que a princípio entendi como a pasta do projeto. Na verdade, parece se referir à pasta de saída do build. Portanto, se eu tiver uma pasta de projeto chamada 'TestFiles' e um arquivo chamado Testdata.xml, usar o atributo desta forma não funciona:

[DeploymentItem(@"TestFiles\Testdata.xml")] 

Posso marcar o Testdata.xmlarquivo Copy Always, para que a construção coloque uma cópia na pasta de saída (por exemplo, Debug\TestFiles\TestData.xml). O mecanismo de implantação encontrará então a cópia do arquivo localizada naquele caminho ( TestFiles\Testdata.xml) em relação à saída da compilação. Ou posso definir o atributo desta forma:

[DeploymentItem(@"..\\..\TestFiles\Testdata.xml")] 

e o mecanismo de implantação encontrará o arquivo original. Ambos funcionam, mas percebi que, Copy Alwaysocasionalmente, tenho o mesmo problema que tenho ao editar o arquivo app.config em um projeto - se eu não alterar o código ou forçar uma reconstrução, nada aciona a cópia dos arquivos marcados para ser copiado na construção.

user1546704
fonte
O caminho relativo era o problema para mim e isso resolveu. Eu adicionei 2 conjuntos de instruções DeploymentItem, dependendo de como os testes foram executados.
Ed Bayiates
3

Desativei o sinalizador de implantação primeiro. Mas mesmo depois de habilitá-lo, por alguma razão desconhecida, nem mesmo as DLLs de destino seriam copiadas. Acidentalmente, abri a janela Test Run e matei todas as execuções anteriores e magicamente encontrei todas as DLLs e arquivos que eu precisava na pasta de teste na próxima execução ... Muito confuso.

Schultz9999
fonte
2

Eu estava tendo problemas enormes ao tentar implantar os arquivos - tentando todas as sugestões acima.

Então fechei o VS2010; reiniciei, carreguei a solução e tudo funcionou. (!)

Eu fiz algumas verificações; Depois de definir o sinalizador 'Habilitar implantação' em local.TestSetting, você não deve simplesmente executar novamente o teste na janela Resultados do Teste. Você deve remover a execução de teste anterior da IU, por exemplo, executando um teste diferente ou reabrindo sua solução.

Stephen Westlake
fonte
2

Não use DeploymentItem .

É muito difícil configurar corretamente e não estava funcionando com meu executor de teste ReSharper nem com o nativo para MSTEST no Visual Studio 2017.

Em vez disso, clique com o botão direito no arquivo de dados e selecione propriedades . Selecione Copiar para o diretório de saída: Sempre .

Agora em seu teste, faça isso. O diretório é simplesmente o diretório do arquivo relativo ao projeto de teste. Fácil.

    [TestMethod()]
    public void ParseProductsTest()
    {
        // Arrange
        var file = @"Features\Products\Files\Workbook_2017.xlsx";
        var fileStream = File.Open(file, FileMode.Open);
        // etc.
    }

Isso parece funcionar bem com sistemas automatizados de construção e teste.

Jess
fonte
1

Como sempre achei o atributo DeploymentItem uma bagunça, faço a implantação desses arquivos usando o script de pós-construção. - Certifique-se de que os arquivos que deseja copiar tenham a propriedade Copiar Sempre definida. - Modifique o script pós-compilação do projeto de teste para copiar os arquivos da pasta de destino da compilação (Bin \ Debug) para o local onde o teste os espera.

Ismail Hawayel
fonte
1

Experimente isso para o VS2010. Portanto, você não precisa adicionar DeployItems para cada tif.
Remova o

[DeploymentItem(@"files\valid\valid_entries.txt")]  
[DeploymentItem(@"files\tif\")]  

Adicione uma configuração de teste.
- clique com o botão direito no nó da solução no gerenciador de soluções
- Adicionar -> Novo item ...
- Selecione o nó Configurações de teste à esquerda, selecione o item à direita
- Clique em Adicionar

Chame por exemplo TDD

Escolha TDDem TestMenu>Edit Testsettings .

Clique em Implementação. Habilite-o e adicione os arquivos e diretórios que você deseja. Haverá um caminho relativo à solução. Os arquivos serão colocados. Os arquivos originais estão, por exemplo, aqui:

D:\Users\Patrik\Documents\Visual Studio 2010\Projects\DCArrDate\WebMVCDCArrDate\Trunk\WebMVCDCArrDate\Authority.xml  

Quando eu executo meu teste de unidade, ele é copiado para

D:\Users\Patrik\Documents\Visual Studio 2010\Projects\DCArrDate\WebMVCDCArrDate\Trunk\WebMVCDCArrDate.Tests\bin\Debug\TestResults\Patrik_HERKULES 2011-12-17 18_03_27\Authority.xml  

no código de teste eu chamo de:

[TestMethod()]
public void Read_AuthorityFiles_And_ParseXML_To_Make_Dictonary()  
{  
  string authorityFile = "Authority.xml";  
  var Xmldoc = XDocument.Load(authorityFile);  

Não há necessidade de escolher Copiar sempre; coloque os arquivos no testproject; adicione caminhos codificados permanentemente no código de teste. Para mim, essa solução funcionou melhor. Tentei com DeploymentItem, copie sempre mas não foi do meu agrado.

Patrik Lindström
fonte
1

Para aqueles que preferem evitar a confusão de DeploymentItem e seguir a abordagem sugerida por @Martin Peck (resposta aceita), você pode usar o seguinte código para acessar o conteúdo do recurso incorporado:

public string GetEmbeddedResource(string fullyQulifiedResourceName)
{
    var assembly = Assembly.GetExecutingAssembly();
    // NOTE resourceName is of the format "Namespace.Class.File.extension";

    using (Stream stream = assembly.GetManifestResourceStream(fullyQulifiedResourceName))
    using (StreamReader reader = new StreamReader(stream))
    {
        string result = reader.ReadToEnd();
    }
}

Para obter detalhes, consulte este Tópico SO

Sudhanshu Mishra
fonte
1
Tive problemas com Assembly.GetExecutingAssembly () ao executar em um servidor de compilação -> ele retornaria o executor de teste em vez do assembly de teste real. Obter a montagem refletindo-a em um tipo fixo na montagem de teste (por exemplo, sua classe de teste) resolveu isso para mim.
Arno Peters
1

Para mim, a causa raiz era algo totalmente diferente: o código de produção exercido por meus testes era renomear e / ou excluir o arquivo de teste .xml sendo implantado.

Portanto, quando eu executaria meus testes individualmente, eles passariam, mas ao executá-los todos juntos, o segundo teste e o subsequente falhariam com erros de "arquivo não encontrado" (que originalmente eu tinha diagnosticado incorretamente como o DeploymentItem atributo não está funcionando).

Minha solução foi fazer com que cada método de teste individual fizesse uma cópia do arquivo implantado (usando essa técnica ) e, em seguida, fazer com que o código de produção sendo testado usasse o arquivo copiado em vez do original.

Jon Schneider
fonte
1

Gastamos muito tempo com o problema de itens de implantação para resolvê-lo na execução de teste de unidade local e na reunião de teste de unidade da cidade de equipe também. Não é fácil.

Uma ferramenta muito boa para depurar esse problema é o ProcessExplorer . Usando o explorador de processos, você pode verificar onde o Visual Studio está procurando pelos itens de implantação e fazer a correção no projeto. Basta filtrar todas as operações de arquivo em que o caminho contém o nome do arquivo do seu item de implantação e você o verá.

Tomas Kubes
fonte
Eu sei que esta é uma resposta muito antiga, mas se você puder explicar como usa o ProcessExplorer, isso seria útil. Não estou vendo como ver as operações de arquivo, muito menos como filtrá-las ...
David
1

Além do atributo Deployment precisar ser verificado, descobri algo mais sobre o atributo DeploymentItem.

[TestMethod()]
[DeploymentItem("folder\subfolder\deploymentFile.txt")]
public void TestMethod1()
{
   ...
}

Seu deploymentFile.txt precisa ser relativo ao arquivo de solução e não ao testfile.cs.

insira a descrição da imagem aqui

Pavenhimself
fonte
Eu finalmente consegui fazer isso funcionar, tendo minha fonte DeploymentItem relativa ao projeto de teste. Portanto, tenho um projeto na minha solução, "Service.Tests". Lá embaixo, tenho uma pasta "FilesForTests" que contém os arquivos que desejo copiar. Eu usei [DeploymentItem(@"FilesForTests\MyFile.txt", "FilesForTests")]. Eu acho que nós estamos dizendo a mesma coisa?
David
1

Tenho trabalhado nisso no VS2013. Minhas descobertas para fazer isso funcionar:

  • Copiar para o diretório de saída deve ser definido como Copiar se mais recente / Copiar sempre: OBRIGATÓRIO.
  • "Enable Deployment" em .TestSettings: NÃO REQUERIDO. Consegui fazer isso funcionar sem um arquivo .TestSettings.
  • Especificando uma pasta como 2º parâmetro: OPCIONAL. Molda o layout da pasta de saída, funciona bem sem.
  • ESPAÇOS no nome do arquivo: isso me causou dor de cabeça - o arquivo nunca foi copiado. Remover os espaços consertou isso. Ainda não olhei para personagens de escape.

Uma dica que também aprendi da maneira mais difícil: não se esqueça de adicionar esse atributo a cada teste individual. O arquivo é copiado no primeiro teste atribuído no teste, mas permaneceu ausente quando a ordem dos testes mudou e os testes não atribuídos tentaram localizar o arquivo primeiro.

Arno Peters
fonte
Tentei tudo aqui antes de chegar à sua resposta, que foi a última. O culpado: ESPAÇOS NO NOME DO ARQUIVO! Boa frase de destaque.
joelmdev
1
Usando o Visual Studio 2019. "Copiar se mais recente" corrigiu. Eu odeio "Copiar sempre" porque força o projeto a reconstruir em muitos cenários, como depuração ou construção incremental.
Gerardo Grignoli
Acordado. Eu atualizei minha resposta para incluir Copiar se mais recente.
Arno Peters
0

Meu grande "pegadinha" foi a maneira como o DeploymentItem lida com diretórios. Eu estava usando a versão de dois parâmetros com ambos como caminho de diretório contendo subdiretórios que queria implantados. Não percebi inicialmente que ele apenas copia o material no ROOT do diretório e não toda a estrutura de pasta recursiva!

Eu basicamente tinha [DeploymentItem (@ "Foo \", @ "Foo \")] e esperava que ele implantasse meu Foo \ Bar. Eu especificamente tive que alterá-lo para [DeploymentItem (@ "Foo \ Bar \", @ "Foo \ Bar \")] e agora ele funciona perfeitamente.

StalePhish
fonte
0

Eu também enfrentei problemas semelhantes. Eu tenho todas as etapas mencionadas acima, mas ainda não tive sorte. Estou usando o VS2010. Então descobri que $ Menu> Teste> Selecionar Configuração de Teste Ativo> Rastrear e testar impacto foi selecionado. Ele começou a funcionar depois que mudei o rastreamento e teste de impacto para Local . Esta página contém informações muito úteis sobre como copiar arquivos para a pasta de resultados de teste. Sinto que devo adicionar essa experiência também.

MJK
fonte