Autofixture: Le gel d'une simulation ne remplace pas une instance injectée

Créé le 31 juil. 2018  ·  1Commentaire  ·  Source: AutoFixture/AutoFixture

Comportement actuel

Lors de l'injection de deux instances concrètes, la seconde instance remplace la première.

Lors de l'injection d'une instance concrète, suivie d'une instance simulée, la seconde instance ne remplace pas la première.

Cela rend l'idée d'effectuer certains tests qui utilisent un simulacre et certains tests qui utilisent une implémentation (en utilisant un constructeur de classe de test pour partager un appareil entre les tests) assez maladroite.

Comportement attendu

Lors de l'injection de deux instances concrètes, la seconde instance remplace la première.

Lors de l'injection d'une instance concrète, suivie d'une instance simulée, la seconde instance remplace la première.

Exemple de comportement attendu

```C#
en utilisant System.Collections.Generic ;
en utilisant AutoFixture ;
en utilisant AutoFixture.AutoMoq ;
en utilisant Moq ;
en utilisant Xunit ;

espace de noms SomeNamespace
{
AutoFixtureTests de classe publique
{
[Fait]
// Les laissez-passer
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);
    }
}

}
```

question

Commentaire le plus utile

Salut @charles-salmon,

Merci d'avoir pris le temps de signaler cela.

Le comportement que vous observez est _de conception_. Permettez-moi de vous expliquer. ??

Si vous regardez l'implémentation de la méthode Freeze<T> :

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

Vous verrez que tout ce qu'il fait est de créer un spécimen de T et de l'injecter dans le luminaire. En effet, la méthode Freeze est apparue comme un raccourci pratique pour cette opération même. Comme @ploeh l'a écrit dans son article présentant la méthode Freeze en 2010 :

Il s'est avéré que nous avons tellement utilisé cet idiome de codage que nous avons décidé de l'encapsuler dans une méthode pratique. Après quelques débats, nous sommes arrivés au nom Freeze, car nous congelons essentiellement une seule variable anonyme dans l'appareil, contournant l'algorithme par défaut pour créer de nouvelles instances.

Compte tenu de cela, il n'est pas surprenant que le gel du même type T qu'une instance injectée donne la même instance.

Maintenant, pour répondre à votre question :

Cela rend l'idée d'effectuer certains tests qui utilisent un simulacre et certains tests qui utilisent une implémentation (en utilisant un constructeur de classe de test pour partager un appareil entre les tests) assez maladroite.

Étant donné qu'un appareil représente le _contexte_ dans lequel un test s'exécute, vous _pouvez_ certainement avoir plusieurs tests qui partagent le même appareil ; cependant, cela se fait au prix d'un mélange de préoccupations multiples, voire conflictuelles.

Le livre xUnit Patterns le résume bien :

Le plus gros problème avec un appareil partagé est qu'il peut entraîner des "collisions" entre les tests, ce qui peut entraîner des tests erratiques , car les tests peuvent dépendre des résultats d'autres tests. Un autre problème est qu'un appareil conçu pour servir de nombreux tests est forcément beaucoup plus compliqué que l' appareil minimal requis pour un seul test.

Cette "collision" est exactement ce qui se passe lorsqu'un test s'attend à ce qu'un objet de type T soit une instance spécifique, tandis qu'un autre test s'attend T ce que faux objet .

Étant donné que je ne peux pas penser à un scénario de test où il est logique que le même type T à la fois une simulation _et_ une instance concrète (bien que je sois heureux d'avoir tort), je vous suggère d'avoir ces les tests utilisent différents appareils, chacun configuré pour servir son scénario particulier.

>Tous les commentaires

Salut @charles-salmon,

Merci d'avoir pris le temps de signaler cela.

Le comportement que vous observez est _de conception_. Permettez-moi de vous expliquer. ??

Si vous regardez l'implémentation de la méthode Freeze<T> :

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

Vous verrez que tout ce qu'il fait est de créer un spécimen de T et de l'injecter dans le luminaire. En effet, la méthode Freeze est apparue comme un raccourci pratique pour cette opération même. Comme @ploeh l'a écrit dans son article présentant la méthode Freeze en 2010 :

Il s'est avéré que nous avons tellement utilisé cet idiome de codage que nous avons décidé de l'encapsuler dans une méthode pratique. Après quelques débats, nous sommes arrivés au nom Freeze, car nous congelons essentiellement une seule variable anonyme dans l'appareil, contournant l'algorithme par défaut pour créer de nouvelles instances.

Compte tenu de cela, il n'est pas surprenant que le gel du même type T qu'une instance injectée donne la même instance.

Maintenant, pour répondre à votre question :

Cela rend l'idée d'effectuer certains tests qui utilisent un simulacre et certains tests qui utilisent une implémentation (en utilisant un constructeur de classe de test pour partager un appareil entre les tests) assez maladroite.

Étant donné qu'un appareil représente le _contexte_ dans lequel un test s'exécute, vous _pouvez_ certainement avoir plusieurs tests qui partagent le même appareil ; cependant, cela se fait au prix d'un mélange de préoccupations multiples, voire conflictuelles.

Le livre xUnit Patterns le résume bien :

Le plus gros problème avec un appareil partagé est qu'il peut entraîner des "collisions" entre les tests, ce qui peut entraîner des tests erratiques , car les tests peuvent dépendre des résultats d'autres tests. Un autre problème est qu'un appareil conçu pour servir de nombreux tests est forcément beaucoup plus compliqué que l' appareil minimal requis pour un seul test.

Cette "collision" est exactement ce qui se passe lorsqu'un test s'attend à ce qu'un objet de type T soit une instance spécifique, tandis qu'un autre test s'attend T ce que faux objet .

Étant donné que je ne peux pas penser à un scénario de test où il est logique que le même type T à la fois une simulation _et_ une instance concrète (bien que je sois heureux d'avoir tort), je vous suggère d'avoir ces les tests utilisent différents appareils, chacun configuré pour servir son scénario particulier.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

JoshKeegan picture JoshKeegan  ·  6Commentaires

ploeh picture ploeh  ·  7Commentaires

malylemire1 picture malylemire1  ·  7Commentaires

gtbuchanan picture gtbuchanan  ·  3Commentaires

joelleortiz picture joelleortiz  ·  4Commentaires