Ao injetar duas instâncias concretas, a segunda instância substitui a primeira.
Ao injetar uma instância concreta, seguida por uma instância simulada, a segunda instância não substitui a primeira.
Isso torna a ideia de realizar alguns testes que usam uma simulação e alguns testes que usam uma implementação (usando um construtor de classe de teste para compartilhar uma fixação entre os testes) bastante estranha.
Ao injetar duas instâncias concretas, a segunda instância substitui a primeira.
Ao injetar uma instância concreta, seguida por uma instância simulada, a segunda instância substitui a primeira.
`` `C #
using System.Collections.Generic;
usando AutoFixture;
using AutoFixture.AutoMoq;
usando Moq;
using Xunit;
namespace SomeNamespace
{
public class AutoFixtureTests
{
[Facto]
// Passes
public void Should_OverridePreviouslyInjectedString ()
{
const string test1 = "test1";
const string test2 = "test2";
var fixture = new Fixture();
fixture.Inject(test1);
fixture.Inject(test2);
Assert.Equal(fixture.Create<string>(), test2);
}
[Fact]
// Fails
public void Should_OverridePreviouslyInjectedInstance()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var sut1 = new List<int>();
fixture.Inject<IList<int>>(sut1);
fixture.Freeze<Mock<IList<int>>>();
var sut2 = fixture.Create<IList<int>>();
Assert.NotSame(sut1, sut2);
}
}
}
`` `
Olá @ charles-salmon,
Obrigado por dedicar seu tempo para relatar isso.
O comportamento que você está observando é _por design_. Permita-me explicar. 🙂
Se você observar a implementação do método Freeze<T>
:
var value = fixture.Create<T>();
fixture.Inject(value);
return value;
Você verá que tudo o que ele está fazendo é criar um espécime de T
e injetá-lo no acessório. Na verdade, o método Freeze
surgiu como um atalho útil para essa mesma operação. Como @ploeh escreveu em sua postagem apresentando o método Freeze em 2010:
Descobrimos que usamos tanto esse idioma de codificação que decidimos encapsulá-lo em um método de conveniência. Depois de algum debate, chegamos ao nome Freeze, porque essencialmente congelamos uma única variável anônima no aparelho, contornando o algoritmo padrão para a criação de novas instâncias.
Dado isso, não deve ser surpresa que congelar o mesmo tipo T
como uma instância injetada resulta na mesma instância.
Agora, para abordar seu ponto:
Isso torna a ideia de realizar alguns testes que usam uma simulação e alguns testes que usam uma implementação (usando um construtor de classe de teste para compartilhar uma fixação entre os testes) bastante estranha.
Dado que um aparelho representa o _contexto_ no qual um teste é executado, você certamente _pode_ ter vários testes compartilhando o mesmo aparelho ; no entanto, isso vem com o custo de misturar várias preocupações - e possivelmente conflitantes.
O livro xUnit Patterns resume bem :
O maior problema com uma luminária compartilhada é que ela pode levar a "colisões" entre os testes, possivelmente resultando em testes erráticos , uma vez que os testes podem depender dos resultados de outros testes. Outro problema é que um acessório projetado para servir a muitos testes tende a ser muito mais complicado do que o acessório mínimo necessário para um único teste.
Essa "colisão" é exatamente o que acontece quando um teste espera que um objeto do tipo T
seja uma instância específica, enquanto outro teste espera que T
seja um objeto falso .
Já que não consigo pensar em um cenário de teste onde faça sentido para o mesmo tipo T
ser uma simulação _e_ uma instância concreta (embora esteja feliz em provar que estou errado), sugiro que você tenha estes os testes usam acessórios diferentes, cada um configurado para servir ao seu cenário particular.
Comentários muito úteis
Olá @ charles-salmon,
Obrigado por dedicar seu tempo para relatar isso.
O comportamento que você está observando é _por design_. Permita-me explicar. 🙂
Se você observar a implementação do método
Freeze<T>
:Você verá que tudo o que ele está fazendo é criar um espécime de
T
e injetá-lo no acessório. Na verdade, o métodoFreeze
surgiu como um atalho útil para essa mesma operação. Como @ploeh escreveu em sua postagem apresentando o método Freeze em 2010:Dado isso, não deve ser surpresa que congelar o mesmo tipo
T
como uma instância injetada resulta na mesma instância.Agora, para abordar seu ponto:
Dado que um aparelho representa o _contexto_ no qual um teste é executado, você certamente _pode_ ter vários testes compartilhando o mesmo aparelho ; no entanto, isso vem com o custo de misturar várias preocupações - e possivelmente conflitantes.
O livro xUnit Patterns resume bem :
Essa "colisão" é exatamente o que acontece quando um teste espera que um objeto do tipo
T
seja uma instância específica, enquanto outro teste espera queT
seja um objeto falso .Já que não consigo pensar em um cenário de teste onde faça sentido para o mesmo tipo
T
ser uma simulação _e_ uma instância concreta (embora esteja feliz em provar que estou errado), sugiro que você tenha estes os testes usam acessórios diferentes, cada um configurado para servir ao seu cenário particular.