Autofixture: L'application des personnalisations à partir de la classe de base ou de l'interface échoue dans 4.0.0-rc1 (régression)

Créé le 20 nov. 2017  ·  10Commentaires  ·  Source: AutoFixture/AutoFixture

Les tests suivants réussissent dans AutoFixture 3.51.0 mais échouent dans 4.0.0-rc1 :
(même dans le dernier commit du master : c856cd6 )

``` c#
[Fait]
public void ShouldApplyCustomizationsFromBaseClass()
{
var fixture = new Fixture();
luminaire.Personnaliser(c => c.Sans(bc => bc.Id));
var res = luminaire.Créer();
Assert.Equal(0, res.Id);
}

[Fait]
public void ShouldApplyCustomizationsFromInterface()
{
var fixture = new Fixture();
luminaire.Personnaliser(c => c.Sans(bc => bc.Id));
var res = luminaire.Créer();
Assert.Equal(0, res.Id);
}

interface publique IInterface
{
int Id { obtenir; ensemble; }
}

classe publique
{
public int Id { get; ensemble; }
}

classe publique ImplClass : BaseClass, IInterface
{

}
```

question

Tous les 10 commentaires

Merci d'avoir soulevé la question. Eh bien, c'est le changement souhaité et il a été appliqué à dessein.

Auparavant, nous avions un problème lorsque la personnalisation d'un sous-type pouvait affecter un autre sous-type. Par exemple:

```c#
class Base { chaîne publique Common { get; ensemble; } }
classe Enfant1 : Base { }
classe Child2 : Base { }

[Fait]
public void EnsureCustomizationAreNotAffected()
{
var fixture = new Fixture();
luminaire.Personnaliser(c => c.Avec(x => x.Common, "factice"));

var result = fixture.Create<Child2>();

Assert.NotNull(result.Common);

}


In the v3 this test failed, causing a lot of confusion to people. As you might imagine, the scenarios were more complicated and it was very non-obvious why the particular members are not initialized. 

For instance, the following code will not work, which again proves that API is not designed for that.
```c#
fixture.Customize<Base>(c => c.With(x => x.Common, "foo"));

Par conséquent, afin de résoudre ce problème, nous avons modifié l'approche , de sorte que la personnalisation d'un type ne peut désormais

Si vous souhaitez toujours omettre les propriétés de base/interface, vous pouvez utiliser l'extrait suivant :
```c#
classe privée SamePropertySpecification : IRequestSpecification
{
type privé en lecture seule _declaringType;
chaîne privée en lecture seule _name ;

public SamePropertySpecification(Type declaringType, string name)
{
    _declaringType = declaringType;
    _name = name;
}

public bool IsSatisfiedBy(object request)
{
    if (request is PropertyInfo pi)
    {
        return pi.DeclaringType == this._declaringType &&
               pi.Name.Equals(this._name, StringComparison.Ordinal);
    }

    return false;
}

}

[Fait]
public void TestBasePropertyOmitting()
{
var fixture = new Fixture();

fixture.Customizations.Add(new Omitter(new SamePropertySpecification(typeof(Base), nameof(Base.Common))));

var result = fixture.Create<Child1>();
Assert.Null(result.Common);

}
```

Si vous avez fréquemment besoin de cette fonctionnalité, vous pouvez créer votre propre méthode d'extension pour fixture . Cependant, je voterais pour ne pas avoir une telle fonctionnalité prête à l'emploi, car elle semble très déroutante.

Ok, bon à savoir que c'était intentionnel. Je suis tout à fait d'accord pour dire que c'était déroutant, mais si cela peut être appliqué explicitement, c'est une fonctionnalité intéressante. J'essaierai votre extrait (et fera probablement la méthode d'extension).

Au fait : est-ce quelque chose que vous souhaitez ajouter à la liste des modifications importantes ? Cela pourrait empêcher que la même question ne soit posée.

Il n'y a aucun moyen d'opter pour l'ancien comportement pour l'une ou l'autre personnalisation de toutes les personnalisations, n'est-ce pas ?

Est-ce quelque chose que vous souhaitez ajouter à la liste des modifications importantes ?

Eh bien, c'est mentionné dans la section des corrections de bogues . Ce n'est en fait pas un changement décisif, car le comportement précédent n'a jamais été déclaré comme une "fonctionnalité". C'était plutôt un effet secondaire indésirable et il a finalement été éliminé 😉

Il n'y a aucun moyen d'opter pour l'ancien comportement pour l'une ou l'autre personnalisation de toutes les personnalisations, n'est-ce pas ?

Non, je crois qu'il n'y a pas de tel moyen car j'ai totalement retravaillé l'approche.

Veuillez tester l'extrait et s'il fonctionne, n'hésitez pas à clore le problème. Ou laissez-moi savoir si vous avez d'autres questions

Je l'ai modifié pour qu'il fonctionne également pour les interfaces et j'ai créé une méthode d'extension pour qu'elle puisse être utilisée dans 'Fixture.Customize(...)'. Je me sens un peu plus hacky que je ne le voudrais, d'autant plus que la façon dont cela fonctionnait dans la v3 était parfaite pour nous. Mais comme notre seul cas d'utilisation consiste à omettre des propriétés et que cela (le plus important ) fonctionne, cela fera l'affaire. Merci!

@nphmuller Désolé d'avoir cassé votre code soigné et bien rangé et maintenant vous devez survivre Mais je crois que votre sacrifice a été fait pour le bien de nous tous, alors vous ne nous en voudrez pas trop 😅

Aucun blâme du tout. Comprenez parfaitement votre raisonnement et même d'accord. C'est juste nul pour moi

Pourrait plonger dans le problème plus tard pour voir s'il y a un moyen plus propre. Pour l'instant ça va.

Juste par curiosité - quel est votre cas d'utilisation réel pour cela ? Parce que je n'ai jamais rencontré un besoin pour ce type de fonctionnalité. Habituellement, lorsque j'écris un test, je n'ai besoin de personnaliser que le type spécifique, plutôt que de configurer le type de base ou d'interface. Est-ce que vous écrivez une sorte de personnalisation globale ?

Dans ce cas, nous utilisons AutoFixture comme générateur de données de test pour les tests d'intégration Entity Framework.

Nous avons quelques types de base ou interfaces que nos entités utilisent et qui contiennent des propriétés communes. Id, locataire-id (et propriété de navigation), des trucs comme ça.

Par exemple, l'une de ces propriétés est l'utilisateur qui a créé l'objet. Cette propriété n'est pas très intéressante pour la plupart des tests, et si elle était générée, elle créerait un énorme graphique (la classe User a également de nombreuses propriétés de navigation) qui devrait être générée et insérée dans la base de données. Cela ralentirait le test ou même échouerait au niveau de la base de données car l'objet n'était pas censé être inséré de cette façon.

Il est donc plus facile d'exclure simplement ces propriétés et de les activer si nécessaire. Au niveau de la classe de base, car sinon la même règle d'omission devrait être écrite pour chaque type d'entité.

@nphmuller Merci pour la clarification, maintenant c'est clair 😉 Oui, il semble que le scénario ait du sens, mais je dois admettre que cela ressemble à quelque chose dont vous avez besoin assez rarement.

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

Questions connexes

mjfreelancing picture mjfreelancing  ·  4Commentaires

zvirja picture zvirja  ·  8Commentaires

ploeh picture ploeh  ·  7Commentaires

zvirja picture zvirja  ·  4Commentaires

DeafLight picture DeafLight  ·  5Commentaires