Temos muitos testes usando 'Class.ReceivedCalls ()' e 'var tmp = Class.Received (int) .Property;' para verificar a contagem de chamadas. Na v3 do AutoFixture ele relatou corretamente a contagem de chamadas, especialmente de Propriedades, o que não é mais feito. A contagem de chamadas dos métodos parece ainda estar ok.
Dado que temos o seguinte código:
public interface IRunSpeed
{
int Speed { get; }
}
public class GetToDaChoppa
{
private readonly IRunSpeed _runSpeed;
public GetToDaChoppa(IRunSpeed runSpeed)
{
_runSpeed = runSpeed ?? throw new ArgumentNullException(nameof(runSpeed));
}
public void DoItNow()
{
var runningSpeed = _runSpeed.Speed;
}
}
E dado que temos os seguintes testes:
[Fact]
public void DoItNow_WithOutAutoNSubstitute()
{
// Arrange
var runSpeed = Substitute.For<IRunSpeed>();
runSpeed.Speed.Returns(2);
var sut = new GetToDaChoppa(runSpeed);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());
}
[Theory, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());
Meu AutoNSubstituteDataAttribute é assim:
public class AutoNSubstituteDataAttribute : AutoDataAttribute
{
public AutoNSubstituteDataAttribute()
: base(() => new Fixture()
.Customize(new AutoNSubstituteCustomization()))
{
}
}
O primeiro teste 'DoItNow_WithOutAutoNSubstitute' está funcionando bem. Mas o segundo teste 'DoItNow_UsingAutoNSubstitute' retorna 2 para 'ios.Received (1) .Speed;'.
Ele também retorna 2 para 'runSpeed.ReceivedCalls ();'.
Por causa disso, atualmente não podemos atualizar nossas soluções para v4, pois instantaneamente temos mais de 1000 testes com falha por solução. Alguma orientação sobre qual pode ser o problema ou onde procurar a solução?
Obrigado por disparar o problema. Na verdade, esse problema não tem nada a ver com a AutoFixtura, embora também possamos ser afetados por ela 😕
Esse problema é causado principalmente pelo xUnit e se você reescrever o teste da seguinte forma, ele passará:
`` `c #
[Teoria, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute_CreateManually (IFixture fixture)
{
// Arranjo
var runSpeed = fixture.Freeze
var sut = fixture.Create
runSpeed.Speed.Returns (49);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());
}
`` `
Quando você executa os testes, o xUnit tenta formatar o nome do teste para você. Se ele descobrir que o tipo não é conhecido e não tem sobrecarga de ToString()
, ele usa a inspeção estrutural e busca recursivamente os valores da propriedade. Se você verificar o nome do teste, verá o seguinte:
Como você pode notar, o xUnit buscou o Speed
da propriedade
É muito estranho que você não tenha esse problema com a v3, pois nada mudou a esse respeito. Acabei de testar o xUnit2 + AutoFixture v3
e ainda tenho o problema. Provavelmente, você também atualizou o xUnit.
Quanto à solução alternativa, tenho boas e más notícias. A boa notícia é que isso será resolvido na próxima versão principal do NSubsitute, pois ele começou a substituir o método ToString()
para retornar um id de proxy. Como resultado, o xUnit não toca mais nas propriedades:
A má notícia é que o NSubsitute v4 ainda não foi lançado.
Eu poderia sugerir a você:
master
recente do NSubsitute, faça uma compilação local e use seu próprio NSubsitute.dll
vez do pacote NuGet. Após o lançamento da v4, você pode alternar para o pacote NuGet.Peço desculpas pelo transtorno, mas, infelizmente, não podemos fazer nada no lado da correção automática para corrigir esse problema.
acabei de testar isso. finalmente, nossos testes afirmando ReceivedCalls voltaram a ter um resultado bem-sucedido novamente.
Algo que ainda falha são as afirmações em Recebido (x) como Recebido (1). Velocidade Daniel mencionado acima.
Você também tem uma resposta / solução para o chapéu?
Vocês estão trabalhando no mesmo projeto? :) Em caso afirmativo, você poderia esclarecer como corrigiu o problema?
As opções sugeridas acima devem ajudar com ambos os problemas. Se não o fizerem, esclareça o cenário.
não é realmente o mesmo projeto, mas na mesma empresa.
estamos usando o xunit 1.9 + nsubstitute 2/3 por um longo tempo e finalmente conseguimos obter nossos assemblies internos (pacotes nuget então uma maneira simples de voltar para uma versão mais antiga de apenas uma referência não é tão fácil quanto parece para ser) para ser compatível com xunit2. e agora temos esses dois problemas.
Já experimentamos algumas coisas e finalmente pensamos que deve ter algo a ver com autofixture - por causa do atributo frozen e uma contagem de execução de teste codificada - ou algo parecido.
depois que Daniel abriu este caso, ele postou o link para mim.
assim como você descreveu acima, substituí a referência do nuget 3.1 por aquela do projeto nsubstitute compilado recentemente. depois disso, agora tenho 118 em vez de 178 testes reprovados porque Recebido (x) ainda está avaliando o número errado de chamadas.
meu projeto é atualmente baseado em .net 4.5.2 com xunit2, versão repo atual do nsubstitute e autofixture 4.2 referenciada. todos os testes estão falhando pelos mesmos dois motivos - também, ainda há algumas chamadas recebidas falhando nos testes de unidade.
Acho que vou ter que dar uma olhada nisso novamente quando estiver de volta ao escritório (para a Páscoa).
talvez @dklinger, entretanto, possa descrever o cenário.
@dklinger @evilbaschdi Por favor, continue depois de ter a chance de verificar isso - é muito interessante porque você ainda verá os problemas, mesmo depois de aplicar o patch.
Reabra o problema para indicar que ainda temos uma investigação em andamento.
Ok, testei nas últimas horas. Em primeiro lugar: Obrigado pela sua resposta, sua explicação e as sugestões - que ajudaram muito.
Eu testei a v4 do NSubstitute. Ele funciona para meu código de exemplo acima, mas não resolve o problema inteiramente em nossos projetos do mundo real. O problema é que ele resolve o problema da contagem incorreta de ReceivedCalls apenas para chamadas SUT para métodos, não para propriedades.
Exemplo de nosso código agora funcionando:
[Theory, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
sut.DoItNow();
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Equal(1, runSpeed.ReceivedCalls().Count());
}
Mas se eu mudar o método "GetToDaChoppa.DoItNow ();" para ser uma propriedade "GetToDaChoppa.DoItNow", o ReceivedCallsCount é +1 novamente:
[Theory, AutoNSubstituteData]
public void DoItNow_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
var x = sut.DoItNow;
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Equal(1, runSpeed.ReceivedCalls().Count());
}
Acho que mais uma vez tem a ver com a nomenclatura xUnit conforme obtemos este para a implementação do método de trabalho:
E aquele para a implementação de propriedade não funcional:
Parece que xUnit está chamando a propriedade SUT para recuperar seu valor e usá-lo para o nome de teste, mas não está fazendo isso para métodos SUT. Meu primeiro pensamento foi que isso tem a ver com o valor de retorno do nosso método "GetToDaChoppa ()" que era nulo. Mas mesmo depois de alterá-lo para "public int GetToDaChoppa ()", o xUnit ainda não o está chamando para obter um valor de retorno para o Nome de teste. É apenas um problema com as propriedades.
Por enquanto, estou preso novamente. Eu concordo totalmente que este não é um problema de AutoFixture. Mas na sua opinião, conhecendo todos os pacotes melhor do que nós, qual seria a sua sugestão?
@dklinger Obrigado pelo acompanhamento! Você poderia compartilhar o código MCVE do último cenário que ainda falha? Apenas para garantir que nada seja esquecido e eu não tenha entendido mal as condições.
Depois disso, tentarei investigar por que isso acontece e como contornar isso.
Obrigado.
Sim, claro. Aqui está:
Sistema em teste:
public interface IRunSpeed
{
int Speed { get; }
void Dude();
int Dude2();
}
public class GetToDaChoppa
{
private readonly IRunSpeed _runSpeed;
public GetToDaChoppa(IRunSpeed runSpeed)
{
_runSpeed = runSpeed ?? throw new ArgumentNullException(nameof(runSpeed));
}
public int DoItNow
{
get
{
var runningSpeed = _runSpeed.Speed;
return 0;
}
}
}
Caso de teste:
[Theory, AutoNSubstituteData]
public void DoItNowAsProperty_UsingAutoNSubstitute(
[Frozen] IRunSpeed runSpeed,
GetToDaChoppa sut)
{
// Arrange
runSpeed.Speed.Returns(49);
//Act
var x = sut.DoItNow;
//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Equal(1, runSpeed.ReceivedCalls().Count());
}
Atualmente, estou tentando acompanhar as discussões em https://github.com/xunit/xunit/issues/1386 e https://github.com/AutoFixture/AutoFixture/issues/805. Talvez estejamos fazendo algo errado ou haja uma maneira de dizer ao xUnit para não gerar automaticamente o nome do teste.
Também tentei criar meu próprio TheoryAttribute substituindo a propriedade DisplayName, mas isso também não ajudou, pois xUnit de alguma forma ainda está usando o nome gerado automaticamente internamente. Mas isso é apenas fyi e totalmente sem relação com o código de demonstração acima.
public sealed class MyTheoryAttribute : TheoryAttribute
{
public MyTheoryAttribute([CallerMemberName] string memberName = null)
{
DisplayName = "MyTestCase";
}
}
Olá, eu de novo :)
Na verdade, é xUnit2 chamando todas as propriedades e campos dos parâmetros do método de teste que são de um tipo complexo. A linha de código é esta: https://github.com/xunit/assert.xunit/blob/2b70a9b0c5bb291f98472ec24cec437acf8d65c8/Sdk/ArgumentFormatter.cs#L156
Obrigado por seu apoio. Reabri um problema no xUnit-Repo, onde a discussão deve continuar: https://github.com/xunit/xunit/issues/1682
@dklinger Obrigado pelo cenário detalhado. É realmente muito complicado e é difícil de alguma forma contornar isso. Da perspectiva de AutoFixture e NSubsitute, não há diferença se o código é chamado em algum lugar profundamente dentro do xUnit ou no corpo de teste.
Normalmente, como solução alternativa, você pode usar o recurso claro do NSubstitute:
runSpeed.ClearReceivedCalls();
Este código deve ser executado no prólogo de cada teste, onde você verifica o número exato de chamadas. Funciona bem se você tiver alguns testes, mas obviamente, se milhares de testes forem afetados, não ajudará muito 😅
É uma pena que a integração NSubsitute + xUnit2 + AutoFixture não funcione bem e sofra com este tipo de problemas. O produto AutoFixture foi projetado para simplificar a vida, ao invés de torná-la um pesadelo 😕 Espero que os caras do xUnit lhe aconselhem uma maneira rápida de resolver o problema em todo o projeto.
Deixe-me saber se você acredita que podemos fazer algo de nossa parte para melhorar a situação.