Nunit: Testes de unidade com falha em nunit.framework.tests após novo clone

Criado em 25 jun. 2018  ·  31Comentários  ·  Fonte: nunit/nunit

Acabei de pegar um novo clone de nunit e abrir a solução no Visual Studio 2017 (Community 15.7.4) com o mais recente NUnit 3 Test Adapter (3.10 com Run Tests in Parallel) em execução no Windows 10 Professional e selecionar "Debug-AnyCPU "e clique em construir.

Depois de ler o BUILDING.md, parece que devo ignorar quaisquer falhas que não venham de nunit.framework.tests- * e nunitlite.tests- *

No entanto, desde o início, recebo 2 falhas de nunit.framework.tests- *

Primeiro erro:

Test Name:  TestCaseSourceCanAccessWorkDirectory("C:\\Users\\ace.olszowka\\source\\nunit\\bin\\Debug\\net20")
Test FullName:  NUnit.Framework.TestContextTests.TestCaseSourceCanAccessWorkDirectory("C:\\Users\\ace.olszowka\\source\\nunit\\bin\\Debug\\net20")
Test Source:    C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\TestContextTests.cs : line 110
Test Outcome:   Failed
Test Duration:  0:00:00.001

Result StackTrace:  at NUnit.Framework.TestContextTests.TestCaseSourceCanAccessWorkDirectory(String workDirectory) in C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\TestContextTests.cs:line 112
Result Message: 
Expected string length 34 but was 50. Strings differ at index 34.
  Expected: "C:\\Users\\ace.olszowka\\source\\nunit"
  But was:  "C:\\Users\\ace.olszowka\\source\\nunit\\bin\\Debug\\net20"
  -------------------------------------------------^

Olhando para a fonte, não vejo como isso foi possível, pelo que posso dizer, esses valores deveriam ser idênticos ( _workDirectory e os dados de teste estão ambos definidos como TestContext.CurrentContext.WorkDirectory ) meu único acho que é algum tipo de condição de corrida, talvez devido à configuração ruim do meu lado?

Segundo erro:

Test Name:  StackTracesAreFiltered("WarningInBeginInvoke",4)
Test FullName:  NUnit.Framework.Assertions.WarningTests.StackTracesAreFiltered("WarningInBeginInvoke",4)
Test Source:    C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\Assertions\WarningTests.cs : line 292
Test Outcome:   Failed
Test Duration:  0:00:00.004

Result StackTrace:  at NUnit.Framework.Assertions.WarningTests.StackTracesAreFiltered(String methodName, Int32 maxLineCount) in C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\Assertions\WarningTests.cs:line 310
Result Message: 
Multiple failures or warnings in test:
  1) (Warning message)
  2) Expected the number of lines to be no more than 4, but it was 5:

 1. at NUnit.TestData.WarningFixture.<>c__DisplayClass45_0.<WarningInBeginInvoke>b__0()
 2. at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)
 3. at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)
 4. at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Object o)
 5. at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
(end)

Eu me perco no que este teste está tentando fazer aqui; mas, com base no meu entendimento limitado, parece que este código é realmente sensível a quaisquer alterações na pilha de chamadas, isso poderia ser devido a uma alteração recente no .NET Framework?

Eu também recebo cada caso de teste com falha em NUnitLite.Tests.CommandLineTests. Eu ficaria feliz em pesquisar lá se isso for inesperado.

Vendo que a compilação está passando em CI, provavelmente são apenas problemas de configuração do meu lado, mas nada foi mencionado em BUILDING.md sobre isso, então percebi que valeu a pena um relatório.

bug normal

Todos 31 comentários

Obrigado pelo relatório! Confirmei que TestCaseSourceCanAccessWorkDirectory e CommandLineTests não funcionam no Test Explorer. Precisamos encontrar uma maneira de torná-los independentes do corredor e do paralelismo. @ nunit / framework-team Alguma ideia?

Para o segundo erro, é um teste de cheiro. Faz sentido aumentar para 5.

No passado, eu apenas dizia às pessoas para não usarem o explorador de testes para os testes NUnit. Outros membros da equipe contestaram o ditado de que o test explorer se tornou, para muitas pessoas, a maneira padrão de executar testes.

Certamente, há um amplo precedente para um determinado runner não ser útil ao testar uma estrutura de teste. Os frameworks de teste em teste são uma situação muito especial e não é encontrada pela maioria dos usuários. OTOH, se a equipe desejar, talvez você tenha como objetivo ser capaz de executar com sucesso o explorador de teste através do adaptador.

Faça o que fizer, acho que você provavelmente deve publicar alguma documentação que diga às pessoas que a execução de testes NUnit no explorador de testes não funciona atualmente. Nesse contexto, você pode dizer a eles que é uma meta fazer funcionar ou que não é uma prioridade, o que for decidido.

Como o primeiro autor do adaptador e um colaborador de muitos anos para a estrutura, sempre reclamei o uso do explorador de teste no desenvolvimento do NUnit. Essa ainda é minha opinião sobre o assunto. Caramba, eu nem gosto que usemos o console para testar o framework em nosso CI agora !!!

Seja qual for a decisão, acho que você terá que continuar enviando pessoas de volta para os corredores NUnit reais (NUnitLite ou o corredor do console) quando surgirem problemas que podem ou não ser devido ao adaptador. O adaptador permanece fundamentalmente equivalente a um executor de terceiros, mesmo se estiver no Projeto NUnit.

FWIW de fora olhando para dentro: Realmente não me importa como ele corta, desde que esteja documentado como tal.

Pronto, eu, como desenvolvedor, tentarei fazer o que normalmente faria quando encontrar qualquer novo projeto que use as mesmas práticas que uso internamente:

  1. Clone o código
  2. Leia o README.md/BUILD.md/HACKING.md
  3. Tente uma construção (sem alterações)
  4. Execute os testes de unidade (por meio do Runner integrado).
  5. Se tudo funcionar, comece a brincar com as coisas.

No passado, isso teria sido o dotCover do ReSharper, mas estamos tentando nos livrar dele, pois os custos de licenciamento são loucos para pequenas lojas / desenvolvedores individuais quando existem alternativas de software livre / de código aberto que "funcionam principalmente".

Há muito (na minha opinião) no conceito de Ambiente de Desenvolvimento Integrado, não ter que sair do fluxo de trabalho é muito útil, e é por isso que o fazemos.

No entanto, se for esperado que usemos o Console Runner (ou algum outro Runner), estou bem, apenas documente.

Se você está desenvolvendo no NUnit, trabalhando no framework, acho que misturar qualquer runner que faça coisas de maneiras especiais (R #, nosso próprio adaptador) pode confundir o problema. Gosto de saber que o framework funciona corretamente de forma isolada antes de testá-lo com os runners. Portanto, em meu próprio trabalho, uso o nunitlite para testar à medida que desenvolvo e, em seguida, executo o CI localmente. Se uma pessoa quisesse desenvolver no NUnit no Test Explorer, eu diria que ela ainda deveria executar o CI localmente e também recorrer ao nunitlite ou ao nunit3-console quando algo parecer duvidoso.

Para as pessoas que estão executando os testes de nunit de uma versão específica, acho que há muito mais latitude.

Devemos tornar o CI canônico, provavelmente com NUnitLite para todos os testes de estrutura e, em seguida, o console, o adaptador VSTest e um executor UWP para testes ponta a ponta.

Presumindo que o CI seja sólido, parece normal para mim se houver diferenças sutis entre o Test Explorer, ReSharper, NCrunch e nosso script de CI. Dizer que essas ferramentas no IDE devem ser ignoradas é algo que vejo como uma barreira à contribuição e é falso, pois esse nem mesmo é meu fluxo de trabalho. Meu fluxo de trabalho ideal:

  1. Localize os testes existentes ou escreva novos testes
  2. Fixe esse dispositivo de teste para tornar mais rápido executar os testes durante a digitação (melhor ainda, comece o teste contínuo)
  3. Implementar uma mudança
  4. Antes de criar um commit do Git, execute .\build.ps1 -t test para garantir que as aprovações e falhas sejam as esperadas
  5. Se houver alguma surpresa, encontre e fixe os testes afetados que eu não conhecia e vá para a etapa 3

No raro cenário em que os testes são sensíveis ao runner, não tenho certeza se é um desafio torná-los insensíveis ao runner. Não pode ser pior do que os testes de integração que escrevi para ILMerge, os quais tornei resilientes para cópias de sombra ReSharper e NCrunch.

@aolszowka Concordo 100% com seu ponto de que tudo o que fazemos, devemos respeitar o tempo dos contribuidores, mantendo os documentos de contribuição fáceis de consumir e atualizados.

@ jnm2 Gosto da sua abordagem "canônica". Tenho dúvidas de que será fácil fazer tudo funcionar perfeitamente no Test Explorer, mas vale a pena tentar.

Ainda é útil, é essencial para qualquer pessoa que esteja trabalhando no nunit saber quando mudar para um nível inferior de teste.

A maior coisa que poderíamos fazer para levar essa ideia adiante na IMO é estabelecer um sistema separado e talvez testes de integração.

Essa pode ser a causa raiz. Ao escrever testes para obter XML do FrameworkController, percebi que TestContext.WorkDirectory estava sendo alterado para C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE :

https://github.com/nunit/nunit/blob/81fcc7c047c09fcb5a86989d0829716ca7d08e1e/src/NUnitFramework/framework/Api/DefaultTestAssemblyBuilder.cs#L137

Pilha de chamadas:

>   nunit.framework.dll!NUnit.Framework.Api.DefaultTestAssemblyBuilder.Build(System.Reflection.Assembly assembly, string suiteName, System.Collections.Generic.IDictionary<string, object> options) Line 137    C#
    nunit.framework.dll!NUnit.Framework.Api.DefaultTestAssemblyBuilder.Build(string assemblyNameOrPath, System.Collections.Generic.IDictionary<string, object> options) Line 114    C#
    nunit.framework.dll!NUnit.Framework.Api.NUnitTestAssemblyRunner.Load(string assemblyNameOrPath, System.Collections.Generic.IDictionary<string, object> settings) Line 154   C#
    nunit.framework.dll!NUnit.Framework.Api.FrameworkController.LoadTests() Line 204    C#

É porque TestContext.WorkDirectory é um estado estático mutável:

https://github.com/nunit/nunit/blob/81fcc7c047c09fcb5a86989d0829716ca7d08e1e/src/NUnitFramework/framework/TestContext.cs#L96 -L101

Isso significa que é compartilhado por todos os testes (!), Incluindo os concorrentes. Qualquer teste que dependa do WorkDirectory deve ser marcado [NonParallelizable] para ser correto.

Percebi esse problema há muito tempo. Há um problema em algum lugar.

NonParallelizable não é suficiente. Se algum teste modificar o WorkDirectory (como muitos dos testes NUnit fazem), há uma probabilidade razoável de que outros testes que dependem dele falharão.

Tudo depende da ordem em que os testes são executados, que é indefinida no NUnit.

A intenção é que o diretório de trabalho seja definido uma vez e permaneça inalterado durante a execução. Qualquer outra coisa é um bug.

Existe uma razão pela qual não podemos permitir um diretório de trabalho independente para cada contexto de execução?

@CharliePoole Como faríamos isso uma realidade? Estamos em uma posição especial, pois o framework testa o teste FrameworkController, um controlador executado dentro de um controlador executado.

Deixando de lado nossos testes, o significado de WorkDirectory é "o diretório definido pelo usuário para receber todos os arquivos de saída para a execução." Portanto, um teste não deve ser capaz de alterá-lo.

Para nossos próprios testes, precisamos ser capazes de defini-lo, mas essa configuração não deve afetar outros testes, se fizermos certo. Provavelmente não estamos fazendo certo. 😜

Em uma pitada, poderíamos torná-lo imutável e parar de testá-lo. <ducks>

Essa é realmente uma ideia legal - rastrear se o campo estático foi definido e pular a configuração depois disso? Dessa forma, ele é imutável e não estou vendo nenhum teste que verifique se DefaultTestAssemblyBuilder define, então devemos ser bons!

Existem testes NUnit que o alteram e, se for tornado imutável, eles podem falhar.

@oznetmaster Eu pesquisei, mas não consigo encontrar nenhum teste NUnit que o altere, exceto acidentalmente. Você tem algum em mãos?

Eu teria que pesquisar meus arquivos.

Já resolvi o problema em minha construção de CF, fazendo o que foi discutido. Permitindo que o valor seja definido apenas uma vez. Eu verifico se ele é nulo e, se for, permito que seja definido.

                if (options.ContainsKey (FrameworkPackageSettings.WorkDirectory))
                    TestContext.DefaultWorkDirectory = options[FrameworkPackageSettings.WorkDirectory] as string;
                else
                    if (TestContext.DefaultWorkDirectory == null)
                        TestContext.DefaultWorkDirectory = Directory.GetCurrentDirectory ();

Os testes que causavam o problema eram aqueles que chamavam DefaultTestAssemblyBuilder.Build com opções que não incluíam FrameworkPackageSettings.WorkDirectory, fazendo com que TestContext.DefaultWorkDirectory fosse sobrescrito pelo CurrentDirectory. Isso significava que, se o WorkDirectory tivesse sido definido na execução de nível superior, seria substituído pelo teste e nunca restaurado.

Parece que seria bom seguirmos a mesma abordagem, então?

Funciona para mim. Minha construção CF passa em 100% dos testes NUnit.

@OmicronPersei Se você estiver por perto nos próximos dias, pode experimentar a correção do ?

Sim! Tentarei esta noite

Não consigo reproduzir esse bug porque o nunit3-vs-adapter # 528 está causando outros problemas. Ideias?

@OmicronPersei Oh. Não sei. Usar um .runsettings com WorkDirectory definido corretamente seria uma boa solução alternativa?

Ok, eu tentei isso. TestCaseSourceCanAccessWorkDirectory é bem-sucedido, mas StackTracesAreFiltered falha com a mesma mensagem / rastreamento de pilha no OP.

Acho que StackTracesAreFiltered deve ser aumentado para 5. É um teste de cheiro para que possamos notar se novos quadros são adicionados para que possamos ter certeza de que não saiu do controle.

E quanto a TestCaseSourceCanAccessWorkDirectory , ou isso ainda está no escopo deste PR?

ForTestCaseCanAccessWorkDirectory, a correção de @oznetmaster resolveu isso? Caso contrário, teremos que investigar mais.

Não consigo reproduzir o problema na minha máquina, o teste em questão foi aprovado para mim.

Não se preocupe, outra pessoa pode fazer essa parte. Eu gosto de ter PRs menores também.

Apenas tentando fazer a limpeza da casa; há algum motivo para esse problema ainda estar aberto ou podemos fechá-lo com algum tipo de resolução? (Mesmo que seja WONTFIX).

Não, obrigado por apontar isso. Fechando.

Esta página foi útil?
0 / 5 - 0 avaliações