Nunit: TimeoutAttribute não disponível ao direcionar a estrutura netcoreapp

Criado em 30 jun. 2016  ·  63Comentários  ·  Fonte: nunit/nunit

Parece que o TimeoutAttribute não está disponível na versão portátil do NUnit 3 ao direcionar o .NET core com um teste netcoreapp. Isso é extremamente útil para qualquer tipo de teste envolvendo threading ou teste de integração, então seria muito útil se isso fosse disponibilizado.

Usando: NUnit 3.4.0, dotnet-test-nunit 3.4.0-beta1.

done enhancement normal

Todos 63 comentários

Esperamos reimplementar o tempo limite e outros recursos que foram eliminados no PCL quando adicionamos uma versão padrão da rede da estrutura. Eles foram descartados porque o tempo limite requer threads que não estão disponíveis no PCL.

Existe algum cronograma para ativar TimeAttribute e DelayedConstraint para a versão netstandard? No momento, estamos portando nossas bibliotecas para o .NET Framework e .NET Core, mas nossos conjuntos de testes fazem uso intenso de DelayedConstraint em particular, de forma que portá-los para oferecer suporte a ambas as plataformas seria uma dor.

A primeira etapa da migração para o .NET Standard está concluída. Esperançosamente, podemos ler os atributos das bases de discussão, Q1

Editar: ignore o abaixo - perdi a classe ThreadUtility, que não pode ser convertida imediatamente.

Eu estava pensando em reimplementar essas coisas de uma maneira baseada em tarefas, mas descobri que System.Threading.Thread está realmente disponível para .NET Standard 1.3.

https://www.nuget.org/packages/System.Threading.Thread/~~

O suporte de plataforma cruzada real é aparentemente um pouco superficial , mas não de uma forma que eu acho que nos afetaria - nosso runner UWP usará a compilação PCL (ou netstandard 1.0 subsequente) para o previsível.

Você ficaria feliz se trouxermos este pacote ou foi algo que você especificamente não fez?

Eu estava planejando puxar o pacote de encadeamento quando começarmos a funcionalidade sustentável. E o utilitário Thread não é conversível?

Thread.Abort () e outros semelhantes não estão disponíveis no .NET Standard. (Eu não acho?) Isso é usado para matar o thread usado para tempos limite.

DelayedConstraint funciona com System.Threading.Thread - eu poderia empurrar isso como um PR separado e, em seguida, revisitar algo Task baseado em Timeouts?

O motivo pelo qual eu não queria converter tudo para ser baseado em tarefas é que eles não estavam disponíveis pré-.NET4, então seriam necessárias duas implementações separadas para pré e pós-NET4. Portanto, por que eu acho que puxar o pacote é bom para o uso de thread em DelayedConstraint, em vez de convertê-lo para usar Task.Delay () em vez de Thread.Sleep (). Pensamentos?

https://github.com/abbotware/nunit-timeout <- código de amostra para criar um atributo .Net Core Timeout

btw, se houvesse um ExecuteAsync no TestExecutionContext, isso poderia ser facilmente convertido em uma variante de Cancelamento cooperativo .. mas o método [Teste] precisaria de uma nova variante que aceite um Cancelamento de Expressão

Eu teria uma preferência em ter nosso comando de método de teste injetar um CancelToken em vez de criar novos threads ou tarefas para testes com tempos limite e deixá-los vazar. Por exemplo, e se uma espera de rotação der errado e atrelar uma CPU para o restante da execução do teste?

Além disso, se ativarmos um novo thread e deixá-lo em execução, como isso interage com [NonParallelizable]?

se um teste está 'travado' - todas as apostas estão canceladas - eu acho que obter resultados parciais é melhor do que nenhum resultado - pior caso adicione uma sobrecarga especial ao tempo limite (100, AbortTestRun = true) <- isso significa que se este tempo limite - Programa. Saída()

Co-op é a técnica mais limpa. Acho que todos estaríamos na mesma página aqui: o trabalho de E / S foi cancelado, os recursos foram descartados, etc.
A próxima etapa mais limpa é você mesmo implementar diretamente o tempo limite - por exemplo, Assert.That(process.WaitForExit(10_000)); vez de process.WaitForExit() ou o método de extensão task.WithTimeout que parece ter escrito seis vezes este ano.

Além disso, fica complicado, porque a próxima coisa mais limpa a fazer é liberar os resultados do teste atual de volta para o executor e encerrar o processo. Isso exigiria uma colaboração cuidadosa entre o executor e a estrutura.
Então, partindo disso, a próxima coisa mais limpa é deixar o thread em execução pelo resto da vida útil do processo host. Na verdade, acho que isso é preferível a abortar o encadeamento, uma vez que o estado global pode ser corrompido em um grau arbitrário devido a tanto código que não precisa ser protegido contra abortos de encadeamento, e você corre o risco de afetar os outros testes.

Não queremos que você perca os resultados do seu teste. Podemos ter alguns exemplos específicos de código que trava testes, onde você não pode contornar isso com using (var cancel = new CancellationTokenSource(10_000)) e passando o token, ou Assert.That(foo.Wait(10_000)) ?

Não estou argumentando que o cancelamento cooperativo seja o mais limpo ... Simplesmente não é realista ... Nem todo código do mundo está no novo modelo Async (nem o segue corretamente, mesmo que seja .. ie 'Bad Actor 'cenário) ... Nem todo código em um teste de unidade está sob controle pelo redator de um teste ....

Estou sugerindo o seguinte:

  1. Fornecer cancelamento cooperativo
  2. Failback para vazar uma tarefa / thread se o Cancelamento de cooperação não for tratado em um período de tempo especificado
[Test]
[Timeout(1000)]
Task [async] TestMethod(Cancellation Task)
//use version 1, fallback to version 2

Advertência: você não pode fornecer token de cancelamento para esses tipos de testes

[Test]
[Timeout(1000)]
Void TestMethod()
//use version 2

[Test]
[Timeout(1000)]
Task [async] TestMethod() 
//use version 2

@abbotware Concordo que os testes precisam optar pelo cancelamento cooperativo. Como eles sinalizam isso é uma questão de design da API.

No entanto, não podemos usar como padrão o vazamento de threads de teste sob o controle do NUnit. Se você quer dizer threads iniciados pelos testes ou pelo SUT, então sim, isso faria sentido.

Então, o que acontece quando um teste é travado ...? você perde todos os resultados do teste

Você quer dizer preso no sentido de que não podemos nem mesmo matá-lo? Acho que é algo com que lidar se houver um caso de uso em que isso possa acontecer __sem que o redator do teste tente explicitamente fazer com que aconteça__.

Eu conheço vários truques que farão um tópico se recusar a abortar. Mas se eu usar esses truques em meu teste, parece que a falha no cancelamento é minha própria culpa. O médico diz: "Pare de fazer isso!"

Além disso ... no design do NUnit, se vazarmos o encadeamento suspenso, perdemos um dos encadeamentos do trabalhador de teste. Se isso acontecer algumas vezes, perderemos todos esses threads e nenhum teste será executado. É por isso que eu disse que não podemos apenas "vazar" nossos próprios threads, mas podemos vazar threads criados por nossos usuários ou pelo código que eles estão testando.

Para threads que estão particularmente em risco, você pode fazer com que o NUnit dedique um thread ao teste, separado dos threads de trabalho. __Esse tópico__ pode ter vazado com segurança.

a sério? O médico diz: "Pare de fazer isso!" -> o que há de errado com este grupo (Nunit) - você não é a primeira pessoa a fazer tal suposição de que tenho controle sobre todo o código em questão. Não vou repetir tudo o que escrevi aqui; (https://gitter.im/nunit/nunit)

você deve assumir que um teste irá travar (lei de Murphy) - nem todo código fará isso .. mas talvez uma biblioteca de terceiros seja atualizada ... e algum novo comportamento aconteça ... Eu quero ser capaz de executar meus testes e veja o que está impactado ... não é esse o ponto dos testes de unidade / testes de integração?

@abbotware Desculpe, você está irritado. Eu não uso o Gitter, então não vi seu comentário. No entanto, eu olhei para isso agora e não parecia explicar o que você quis dizer, apenas afirmou que você não tem controle. Às vezes, as pessoas não se entendem porque simplesmente vêm de origens diferentes, têm significados diferentes para os termos ou possuem valores diferentes. Ficar bravo não faz a comunicação funcionar melhor.

Meu próprio comentário se refere a __seu código de teste__ e a nada mais. Se uma biblioteca tiver um problema, acho que você deve escrever seu código de teste para lidar com esse problema. Se isso for um problema com o qual muitos usuários do NUnit precisam lidar de forma independente, então é um candidato a um recurso. Mas não há __nenhuma__ projeto de código aberto (ou outro) que entretém recursos para necessidades inexplicáveis, pelo menos não até onde eu sei. Se não entendemos, tentamos entender primeiro.

Não sei sua formação, é claro. Mas a suposição básica do NUnit (e de quase todas as estruturas padronizadas do xUnit) é que seu código de teste está sob seu controle, enquanto o código que você está testando pode ou não estar. Na verdade, existem três níveis de código envolvidos: teste, SUT e bibliotecas de terceiros. Na situação ideal, você tem controle sobre os dois primeiros, porque também está escrevendo o SUT. Mas às vezes não é assim. Por definição, é claro, você não tem controle sobre as bibliotecas de terceiros, mas pode ter controle sobre como usá-las.

Estou explicando isso porque vemos muito mais pessoas hoje em dia que dizem que __não__ têm controle (nem mesmo) sobre os testes. Este é um novo público para mim e não tenho certeza se sei como lidar com isso. Se for essa a sua situação, minhas desculpas. Mas você postou o suficiente aqui que sou levado a supor que __é__ na verdade um desenvolvedor de software com uma boa experiência. Se você estiver disposto a explicar por que ou como não tem controle sobre seus testes, gostaria de ouvir mais porque isso pode nos ajudar a lidar com outras pessoas que não são capazes de articular o problema tão bem quanto você.

@abbotware Então ...

  1. Você tem um teste de trabalho
  2. Uma biblioteca de terceiros é atualizada
  3. Esse teste agora faz com que o NUnit trave sem informações que ajudem a localizar o problema.

Esse é um problema muito específico. Obrigado.

Uma solução aproximada é ver qual teste estava sendo executado quando o travamento ocorreu. Dependendo de como você executa os testes (console, VS, etc.), existem maneiras de descobrir isso. A solução é aproximada, entretanto, porque um teste pode iniciar um thread que impacta o NUnit muito depois que o teste termina.

Sempre tivemos esse problema - ou seja, durante os 18 anos de existência do NUnit - mas ele se torna mais proeminente à medida que mais pessoas usam o multi-threading e o próprio NUnit funciona em paralelo.

Soluções existentes:

  1. Examine o log de rastreamento interno
  2. Use a exibição de etiqueta de teste no console para ver o que estava sendo executado
  3. Use a execução não paralela para que os resultados acima sejam mais fáceis de interpretar

Nenhum deles é 100% satisfatório, então o que você gostaria de ver além deles?

Finalmente, isso realmente está relacionado à indisponibilidade de TimeoutAttribute no .NET Core ou é um problema separado?

Você pode ter certeza de que se eu vir um resultado de [TestTimeout] ... Eu estarei procurando muito para descobrir POR QUE isso ocorreu ... mas como está agora ... Eu não consigo nem obter esse resultado se o testrunner 'travar', Net Core ...

O que é esse 'terceiro' que estou descrevendo .. bem .. isso pode surpreender vocês .. mas é o .Net Core _ITSELF_ Sim ... é bugado e nem um pouco 'perfeito' em processadores linux / arm - então Eu REALMENTE preciso desse recurso

Então, quando eu mudo do net core 2.0 para 2.1, preciso ser capaz de ver se alguém da equipe coreCLR não fez "merda" :-)

Por que tudo que estou fazendo é tão crítico: o software que escrevo funciona 24 horas por dia / semanas / meses a fio com 0 vazamento de memória ou thread em "condições normais" <- as aspas estão lá porque vamos encarar ... "coisas acontecer "- assim como implementei TestTimeout - você precisa fazer um sacrifício por ser 100% purista (algo que considero fanatismo idealista) versus a realidade do mundo real.

Se você perguntar a qualquer um de seus usuários se ele deseja 'Nenhum resultado' porque 1 teste em 1000 causou um travamento ... ou 'Resultados parciais' - qualquer pessoa razoável escolherá o último.

Mesmo que signifique que esses resultados parciais vêm com um grande 'asterisco' - pelo menos eu sei Teste ABC = tempo limite, e todos os testes após ABC dizem - 'Passou - Mas você precisa executar novamente porque Teste ABC = tempo limite, e nós não pode dar nenhuma garantia sobre a validade de 'Passar' - aceite este resultado por sua própria conta e risco - remova ou conserte o teste ofensivo .. e então você ficará bem '

Um pouco pedante, com certeza, mas se você precisar CYA, faça isso ... ou torne essa funcionalidade um recurso para os usuários avançados que sabem o que estão fazendo e a desativam por padrão.

Para o 'registro' - estou perfeitamente satisfeito com meu [tempo limite] - não preciso que o grupo NUnit faça nada - apenas pensei que este pequeno pedaço de informação serviria para outros usuários que parecem estar na mesma ( ou semelhante) situação em que me encontro.

Eu ia tentar contribuir com a versão do método de cancelamento do CoOp bifurcando, cavando no código e enviando um PR ... mas não tenho certeza se minhas visões são alinhadas / consistentes com o projeto em geral.

@abbotware "Este recurso"?

Eu entrei na conversa porque __pareceu__ que você estava fora do assunto em relação __este__ assunto, mas estava dizendo algo interessante. Se o recurso que você deseja é ter Timeout no .NET Core, não estou aqui para argumentar contra você. MAS parecia que você estava dizendo que a semântica existente do Timeout não é útil para você, não entendi bem?

Mesmo que a semântica atual não seja a que você gostaria, não faria sentido primeiro implementá-la no .NET Core e depois discutir as possíveis alterações?

Se eu fosse implementar qualquer coisa, seria minha sugestão acima: (ou seja, 1. cancelar coop, 2. voltar para a tarefa de vazamento)

@ nunit / framework-team Aqui está um pequeno problema simples e agradável que diz que devemos implementar TimeoutAttribute para aplicativos .NET Core. Existe até algum código que foi sugerido.

Eu me pergunto ... não podemos simplesmente corrigir o problema real que foi relatado?

@ nunit / framework-team Para fazer a implementação de vazamento de thread, precisamos decidir se podemos tratar todas as plataformas da mesma forma (ou seja, parar de interromper thread no .NET Framework). Nossas compilações do .NET Standard podem ser executadas no .NET Framework, portanto, se não quisermos alterar o comportamento de interrupção de thread existente, a coisa certa a fazer seria a detecção de recurso via PlatformNotSupportedException. Isso significaria que, antes de executar um teste com [Timeout], precisaríamos detectar se o aborto do thread é possível e, se não, iniciar um novo thread que pode ser vazado.

Nossas compilações .NET Standard também são executadas em UWP, que o IIRC não nos permite iniciar novos encadeamentos, portanto, usando Task.Run , estaríamos emprestando encadeamentos do pool de encadeamentos e (no tempo limite) nunca os retornaríamos. Isso não parece terrível, considerando o quão raros os tempos limite devem ser, embora haja o risco de inanição do threadpool. Isso só aumenta a complexidade do suporte [Timeout] nas compilações do .NET Standard.

@abbotware Agradeço sinceramente seus comentários. Peço desculpas por minha abordagem não ter sido simpática com você. Estou aqui porque quero facilitar a vida dos nossos usuários. Quaisquer dicas específicas seriam altamente valorizadas!

O dilema para mim é que, por um lado, esse recurso parece básico. Nós não apenas fazemos funcionar? MSTest tem? Etc. Isso é uma coisa totalmente razoável de se pensar.
Por outro lado, passei a acreditar (junto com o mantenedor do xUnit) que o Timeout sempre foi uma mentira; além disso, apenas com más escolhas de implementação. Tenho defendido a remoção de seu uso em todas as bases de código em que trabalhei. Além da complexidade de suportá-lo em todas as plataformas .NET Standard, também há a desvantagem de que as pessoas simplesmente alcançarão [Timeout] quando eles têm opções muito melhores.
Então, para me convencer de que adicionar isso ao NUnit poderia ser uma coisa boa, eu estava procurando um caso de uso. Sempre presumo que uma solicitação _não_ é um problema XY, mas não fui capaz de criar cenários de exemplo sem solicitá-los, onde o co-op era impossível ou menos desejável.

Ao ler seus comentários acima, você está procurando uma maneira de garantir que o próprio .NET Core não seja implementado incorretamente de uma forma que introduza um tempo limite. Isso é correto?

@ jnm2 Isso começou com a implementação do TImeout no .NET Core. A discussão mudou rapidamente para encontrar uma implementação __common__ em todas as plataformas e muito recentemente mudou para implementar o cancelamento cooperativo, que é menos do que a solicitação original em uma dimensão e mais do que em outra.

Então ... Estou perguntando, o que há de errado em fazer a implementação simples de TimeoutAttribute oferecido por @abbotware nas plataformas que atualmente não o suportam? Estaremos em situação pior ou melhor do que estamos agora se fizermos isso? Os usuários solicitantes ficarão em situação pior ou melhor?

Minha própria resposta é que os usuários que agora não têm acesso ao Timeout o terão. Pode funcionar um pouco diferente do tempo limite em outras plataformas, mas isso não soa como um quebra-negócio.

O único contexto em que eu não veria uma vantagem na implementação do Timeout para .NET Core é se o projeto pretende tornar obsoleto e remover TimeoutAttribute em todas as plataformas. Mas isso é um absurdo, já que tantos usuários dependem dele apesar de suas limitações.

Fazer o pequeno agora não impede fazer o maior depois.

@CharliePoole - Concordo que o cancelamento do CoOp é uma 'solicitação de recurso' e está fora do escopo da solicitação original. O que eu estava propondo aborda o problema atual como uma solução simples, já que isso tem ... 2 anos!

@ jnm2 - Eu ainda acho que 'cancelamento de CoOp' é o caminho a seguir, mas essa é definitivamente uma pergunta maior. (Mas estou disposto a ajudar!)

Com relação às implementações 'específicas da plataforma': Estou quase certo de que você não precisa detectar isso por meio de uma exceção - Em vez disso, você conhece a configuração de compilação (parâmetros de compilação) + configuração de tempo de execução (OS + Tempo de execução) e pode criar uma matriz / pesquisa de recursos . Eu uso System.PlatformID o tempo todo para alternar entre janelas e variantes de código específicas do Linux em tempo de execução. (você pode até mesmo olhar para o código CLR de referência para ver como ele consegue lançar uma exceção em primeiro lugar!)

quanto ao timeout ser uma mentira - discordo - tem seu valor e acho que já descrevi meu cenário. Eu sei que você está dizendo que um 'usuário' tem opções - eu concordo .. No entanto, qual é o problema em adicionar um recurso à biblioteca que imita o que o usuário faz? Ele adiciona um nível de 'indireção' por meio de uma tarefa ou thread no código do usuário ou por meio do código da estrutura. Nem todos os meus testes têm um parâmetro de tempo limite ... mas para aqueles que têm, eu sei que é porque ele realmente precisa dele e eu prefiro que a tarefa / thread do wrapper seja feita de forma consistente do que deixá-lo para o meu código de usuário potencialmente problemático! (e sim, eu sei que posso fazer métodos de extensão, etc.) mas ainda ... o atributo de teste vence por ser a abordagem mais simples e limpa (da perspectiva do usuário)

@ jnm2 - em resposta a isso: "você está procurando uma maneira de garantir que o próprio .NET Core não seja implementado incorretamente de uma forma que introduza um tempo limite. Correto?"

O fato de meu problema estar ocorrendo no CLR deve ser irrelevante. Uma dependência (direta ou indireta) é alterada. O código que tem qualquer assíncrono (isso é uma palavra?), Funcionalidade de threading ou multiprocesso pode potencialmente causar um deadlock se tiver sincronização. Estou me referindo a instruções de bloqueio , condições de espera, todas as formas de sincronização de thread (mutex, semáforo, etc) ... e hoje em dia 'tarefas' ... podem ter comportamentos diferentes se uma biblioteca for alterada (ou até mesmo o código). Este é o código que desejo testar com o atributo Timeout.

Você não pode presumir que este código está escrito perfeitamente (com tempos limite) nem que um usuário tenha tempos limites corretos em todos os lugares, ou mesmo cancelamentos em cadeia corretamente, ou que eu possa até mesmo alterar o código com problemas. (Para sua informação, uma vez indiquei um bug no código de terceiros para o autor da biblioteca - A chamada assíncrona _não tinha um token de cancelamento_ - a resposta foi "Eu cobro pelo suporte" - minha única opção era apenas usar a versão de sincronização pelo menos um tempo limite)

Eu diria que o cancelamento do CoOp "é uma mentira" - não há como garantir isso. Você não pode. O fato de você ter dito "se você está ignorando o símbolo, está fazendo errado", em primeiro lugar, só prova meu ponto. Tudo tem que estar em perfeito alinhamento.

Isso torna um Timeout como o que estou descrevendo ainda mais valioso para ajudar a identificar o código com problemas.

@ jnm2 - "Nossas compilações .NET Standard também são executadas em UWP, o que o IIRC não nos permite iniciar novos encadeamentos, portanto, usando Task.Run, estaríamos tomando emprestados encadeamentos do pool de encadeamentos e (no tempo limite) nunca os retornaríamos." -

Não estou familiarizado com UWP, mas geralmente se uma tarefa está 'travada', isso não significa 100% um thread perdido. Na melhor das hipóteses, é um vazamento de recurso / memória porque o código do usuário está preso em uma espera em algum lugar: O ponto inteiro de usar o código que pode ser aguardado em primeiro lugar é para que as trocas de contexto possam acontecer, liberando um número limitado de threads para fazer mais trabalho.

Na pior das hipóteses, o código está no espaço do usuário e fazendo um "loop ocupado" infinito <- que é um thread perdido.

@CharliePoole

Estaremos em situação pior ou melhor do que estamos agora se fizermos isso? Os usuários solicitantes ficarão em situação pior ou melhor?

Estou disposto a ser convencido.

@abbotware

Agradeço a oferta de ajuda para o problema do co-op! Podemos aceitar você nisso!

Eu uso System.PlatformID o tempo todo para alternar entre janelas e variantes de código específicas do Linux em tempo de execução. (você pode até mesmo olhar para o código CLR de referência para ver como ele consegue lançar uma exceção em primeiro lugar!)

Eu tentaria evitar isso de forma semelhante a evitar a detecção baseada em versão, mas em uma base caso a caso, é claro. Se há algo mais confiável do que acionar o PNSE, vamos lá! Tenho certeza que o código de referência joga incondicionalmente.

O fato de você ter dito "se você está ignorando o símbolo, está fazendo errado", em primeiro lugar, só prova meu ponto.

Não estou reconhecendo isso como algo que eu diria. O cancelamento cooperativo definitivamente não é o encerramento garantido. Eu acho que a rescisão garantida em si é uma mentira, a menos que você interrompa o processo.

Você não pode presumir que este código está escrito perfeitamente (com tempos limite) nem que um usuário tenha tempos limites corretos em todos os lugares, ou mesmo cancelamentos em cadeia corretamente, ou que eu possa até mesmo alterar o código com problemas.

Eu não poderia concordar mais! Ainda assim, se você estiver em tal cenário enquanto testa seu código, você também precisará resolver os mesmos problemas quando seu código estiver sendo executado em produção sem NUnit. Depois de aplicar a solução de produção, isso não resolveria imediatamente o problema do tempo limite do tempo de teste?

O ponto principal é que os tempos limite acionados por testes são extremamente raros. Você não permitiria que o deadlock permanecesse no código de produção e, assim que encontrá-lo e corrigi-lo, não precisará mais do atributo [Timeout]. O valor que [Timeout] traz que posso ver é:

  • bons resultados de teste relatados, mesmo se os testes subsequentes forem afetados, em vez de não haver resultados para a execução
  • evitando que as compilações autônomas travem por uma hora (já deve ser feito no nível do corredor)

Esses são benefícios legais o suficiente para que eu ficasse feliz se fizéssemos o que fosse necessário em cada plataforma para facilitar esse estágio de diagnóstico. Isso soa certo?

Não estou reconhecendo isso como algo que eu diria.

Eu parafraseei: suas palavras exatas foram:

"Isso é diferente do código de produto de envio que não escuta um token de cancelamento? Se você está se prejudicando ao aceitar um token de cancelamento e não fazer nada com ele, então ... pare de fazer isso"

mas vamos seguir em frente ...


Esses são benefícios legais o suficiente para que eu ficasse feliz se fizéssemos o que fosse necessário em cada plataforma para facilitar esse estágio de diagnóstico. Isso soa certo?

SIM 👍

Incrível, vamos fazer isso! 🎉 Perguntas para recapitulação:

  • É desejável simplificar nosso código sempre vazando um thread no tempo limite em vez de abortar?
  • Se não, estamos de acordo com os assemblies .NET Standard se comportando de maneira diferente dos assemblies .NET Framework, quando ambos estão sendo executados no .NET Framework?

bem - não acho desejável mudar o comportamento existente.

Do jeito que está agora, não há nenhum atributo para o padrão líquido, certo? Então você meio que tem uma ficha limpa:

Outra ideia: [Timeout (1000, AbortIfSupported = true)] (mas isso implica que um thread é criado por teste) - Eu não conheço os internos do NUnit bem o suficiente para dizer se isso é ou não viável

Temos uma ficha limpa. Depois de adicionar TimeoutAttribute , este cenário se torna possível:

  • O projeto de teste de unidade (net472) usa [Timeout] , depende da biblioteca de utilitários de teste comum (net472), que depende do NUnit (puxa a compilação net45)
  • Você muda o utilitário de teste comum para netstandard2.0 que puxa a compilação netstandard2.0 do NUnit. [Timeout] começa a vazar em vez de abortar, tudo durante a execução no .NET Framework.

Isso não parece um problema para mim se todos concordarem com isso?

e o projeto de teste de unidade (netcoreapp)?

@abbotware ❔ Atualmente um projeto netcoreapp não pode ser compilado usando [Timeout] , então não há um cenário análogo ao do .NET Framework.

OK - acho que entendi mal sua afirmação acima - pensei que você pretendia descrever todos os cenários em que o novo (vazamento) Timeout seria introduzido .. .. em vez disso, você está apenas dizendo quais os atuais seriam afetados? (aliás, uma lista exaustiva / explícita de pode precisar ser criada (ou seja, matriz de recursos)

Eu nem sei todos os cenários (e a tabela a seguir pode estar errada em relação ao net452 - eu apenas escolhi uma 'estrutura' aleatória) - mas deixe-me começar:

| NUnit Build | Interrupção do tempo limite | Vazamento de tempo limite |
| --- | --- | --- |
| .net452 | x | n / a |
| NetStandard2.0 | n / a | (novo) |

| Tempo de execução do teste de unidade | Comportamento do tempo limite | Construir Nunit Vinculado
| --- | --- | --- |
| .net452 | abortar | .net452 |
| .net472 | vazamento (mudança?) | NetStandard2.0 |
| NetCoreApp2.0 | vazamento (novo) | NetStandard2.0 |

@ jnm2 - você provavelmente deve saber mais sobre todos os outros cenários de tempo de execução / builds de nunit do que eu - então talvez você possa completar as tabelas acima? Também ajudaria qualquer pessoa que siga esta 'solicitação de recurso' a entender o impacto geral no NUnit

Eu acho que .. é possível vincular um tempo de execução de .net472 -> .net452 (ou mesmo .net2 / 35) - mas, isso é mesmo recomendado? portanto, a tabela pode não ser capaz de incluir todas as permutações, apenas o padrão (via nuget)

@abbotware Ei, eu tentei e estou errado! Toda uma categoria de mudanças com a qual tenho me preocupado não é uma coisa! Nesta situação:

Projeto de teste de unidade ( net461 - net472 )
└ Referências: projeto / pacote auxiliar de teste, netstandard1.4 - netstandard2.0 .
└ Referências: pacote NUnit

O NuGet ainda fará referência à compilação do .NET Framework de NUnit no projeto de teste de unidade, não à compilação do .NET Standard, embora o projeto de teste de unidade não faça referência direta ao NUnit.

Para ver a mudança de comportamento de abortar para vazamento, então, você não teria que ter referências de pacote para NUnit e uma referência manual para um assembly NUnit do .NET Standard. Isso é tão raro que não estou preocupado. Você terá problemas maiores se fizer isso. 😜

@ jnm2 - Estou feliz em pegar isso.

Já tenho uma filial com uma solução de trabalho, ou seja, uso o código abbotware porque funciona. Eu adicionei alguns testes. Posso ir direto ao RP para ver onde estamos, pois percebo que há um pouco de contenção.

Eu me mantive no básico ....

Ótimo - obrigado @DaiMichael ,

Receio que o GitHub não nos permitirá atribuir o problema a você até que você faça parte da 'Organização NUnit' no GitHub, mas removi o rótulo de solicitação de ajuda.

Para corrigir isso: @rprouse - você poderia enviar o convite do Dai para a equipe de colaboradores? Dai - nossa equipe de colaboradores é formada por aqueles que deram algumas contribuições de vez em quando para o projeto NUnit - ela concede algumas permissões básicas, como permitir que coloquemos seu nome nas questões que você escolhe diretamente, e também permite que você faça alterações nos documentos. Depois de suas últimas contribuições, você é mais que bem-vindo, se aceitar!

uh .. então nenhuma atribuição para o código que escrevi? meio que parece que foi apenas copiado e colado lá ...

@abbotware Não há RP ainda. O que você gostaria de ver se seu código fosse usado?

@DaiMichael Enviei um convite para a equipe de colaboradores, seja bem-vindo.

@abbotware normalmente não adicionamos atributos a autores individuais no código, geralmente só fornecemos reconhecimento por meio do gráfico de contribuição para o projeto para pessoas que contribuem com PRs. Poderíamos adicionar um pequeno comentário no código, se você preferir, mas indique isso antecipadamente. Normalmente, quando as pessoas fornecem exemplos de código para que possamos corrigir e emitir ou fornecer um aprimoramento, é para satisfazer suas próprias necessidades.

Considerando que esse problema existe há quanto tempo? ... se não fosse pelo meu código de amostra, este PR não teria sido feito .. e ainda mais, o código de amostra é / foi apenas copiado e colado no PR de outra pessoa . Eu não me importo com o código sendo copiado e colado, pois eu mais do que esperava que isso acontecesse (embora tivesse um cabeçalho de direitos autorais!), E estou feliz que isso esteja sendo mesclado no NUnit adequado ... Mas um pequeno reconhecimento para meu esforço e / ou contribuição seria bom.

por exemplo, eu até atribuí o código para 'Tempo limite após' onde o encontrei:
https://github.com/abbotware/nunit-timeout/blob/master/Abbotware.Interop.NUnit/TaskExtensions.cs

@abbotware Novamente, nenhum PR foi enviado. Posso apenas supor, mas parece improvável que outra pessoa além de você envie um PR usando o seu código, dados seus comentários.

Dito isso, você liberou seu código no GitHub sob a licença MIT, que permite seu uso em outros trabalhos sem atribuição.

O próprio NUnit é lançado sob a mesma licença. As pessoas pegam partes dele, mesmo grandes partes, e incorporam em outras obras o tempo todo. Seria tolice reclamar, já que foi essa a licença que escolhemos.

Estou extravasando minhas próprias opiniões pessoais aqui, BTW. Eles não têm nenhuma conexão com as visualizações do projeto NUnit.

@CharliePoole - Desculpe, pensei que as 'correções # 1638' fossem uma solicitação de relações públicas ...

De qualquer forma - pensei que havia alguma forma de reconhecimento menor (embora não exigido pela licença) para ajudar a resolver esse antigo problema, visto que o método que propus parecia estar sendo submetido.

Parece que isso está se tornando um negócio maior do que o necessário: Por favor, esqueça que perguntei. Vou enviar um PR completo na próxima vez para o reconhecimento 'adequado'.

@abbotware Não, isso é apenas uma correção para o fork do nunit do próprio usuário. É mencionado neste problema porque ele o referenciou em um comentário.

Seu ponto de vista sobre atribuição foi bem entendido. É que você parecia estar endereçando isso para a equipe do NUnit, que não usou o código e nem mesmo está considerando isso agora, já que nenhum PR foi enviado. Tecnicamente, poderíamos sair e pegar o código de qualquer um dos repositórios e usá-lo, mas isso não é algo que normalmente fazemos.

Pergunta de curiosidade: você considerou enviar você mesmo? Você foi muito ativo nesta discussão e isso teria parecido um resultado lógico.

@CharliePoole - Dado que o escrevi como plugin, parecia mais apropriado para um projeto do tipo 'NUnit.Contrib' do que o NUnit propriamente dito. Parabéns por ter grande extensibilidade!

Eu considerei um PR, mas não tinha certeza por onde começar ... Agora, porém, eu meio que tenho uma ideia (graças a @DaiMichael)

Para fazer uma RP ...

  1. Comece com um branch baseado no NUnit master mais recente mais a mudança que você está enviando. Uma coisa de cada vez é melhor. Se você fizer duas mudanças diferentes, a equipe pode gostar de uma, mas não da outra, o que o torna mais lento.

  2. Em seu navegador, liste seus branches no GitHub. Há um botão para clicar e enviar um PR.

  3. Preencha o PR incluindo "Correções #nn" ou "Fechamentos #nn" na descrição, onde nn é o problema que você está corrigindo. Adicione qualquer informação não óbvia sobre o PR.

  4. Dois committers NUnit diferentes precisam aprovar seu PR antes que ele seja mesclado.

Isso é tudo. Os PRs do GitHub são realmente brilhantes!

Para esclarecer - eu quis dizer onde no código NUnit :-)
Dado que está vinculado a questões relacionadas com a construção: Net Core vs Framework etc

Ah! OK então. 😄

A menos que recebamos permissão especial de copiarmos seu código:

https://github.com/abbotware/nunit-timeout/blob/master/LICENSE ( @abbotware é o duplo'w 'intencional?)

Se não quisermos nos preocupar com isso, devemos começar do zero.

É por isso que esperamos por um PR. Ao enviar um PR, o autor concorda em doar o código para nós, o que é diferente de simplesmente encontrá-lo no GItHub. Na ausência de um acordo de contribuição (que provavelmente deveríamos ter), a suposição usual é que o trabalho é do autor do envio ou ele está autorizado a enviá-lo e que o está oferecendo sob a mesma licença que usamos. Se eles enviarem com algo no arquivo que contradiga essa suposição, podemos pedir que alterem ou aceitem como está. Em geral, pedimos que ele seja alterado, mas temos alguns bits que mantemos com direitos autorais dos autores originais, como a implementação .NET 2.0 das classes Linq.

O problema é que muitas pessoas colocam uma declaração de copyright em um arquivo com a intenção de fazer referência a ele. Nós o usamos para nos referirmos aos direitos autorais de todo o trabalho, por exemplo, a estrutura NUnit. Supostamente, íamos obter ajuda da fundação .NET nessas questões, mas parece que nunca chegou.

https://github.com/abbotware/nunit-timeout <- código de amostra para criar um atributo .Net Core Timeout

@CharliePoole podemos adicionar esse código?
Eu verifiquei, está funcionando muito bem.

@Diaver Não sou mais a pessoa

Há um PR em andamento (veja # 3027), mas nada aconteceu desde o final de setembro (e pelo que eu posso dizer @DaiMichael não está ativo no github desde então), também houve a questão dos direitos autorais.

Eu desisto de todas as reivindicações de licença / direitos autorais (pensei que estava claro em meus comentários anteriores) - Basta adicionar / mesclar o código para NUnit :-)

Obrigado pelo esclarecimento @abbotware.

@DaiMichael @ jnm2 parece que vocês estão chegando perto de fundir o PR # 3027 para corrigir esse problema. Ainda estão trabalhando nisso?

@sebastienpa - Não tenho certeza do que está acontecendo com o PR, mas escrevi um plugin / extensão como uma prova de conceito há algum tempo e lancei uma versão funcional como um nuget. se não quiser esperar pelo PR, pode usar o nuget "Abbotware.Interop.NUnit"

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