web-dev-qa-db-fra.com

Assertion XUnit pour vérifier l'égalité des objets

J'utilise le framework XUnit pour tester mon code C #.

Existe-t-il une méthode d'assertion disponible dans ce cadre qui effectue la comparaison d'objets? Mon intention est de vérifier l'égalité de chacune des variables membres publiques et privées de l'objet.

J'ai essayé ces alternatives mais ça marche rarement:

1) bool IsEqual = (Obj1 == Obj2)
2) Assert.Same(Obj1, Obj2) which I couldnt understand what happens internally
27
inquisitive

Vous devez disposer d'un comparateur personnalisé pour y parvenir, lorsque vous comparez des objets, sinon ils sont vérifiés selon qu'ils se réfèrent au même objet en mémoire. Pour remplacer ce comportement, vous devez remplacer la méthode Equals et GetHashCode et vous pourriez alors faire:

Assert.True(obj1.Equals(obj2));

Voici une page MSDN abt surchargeant la méthode Equals: http://msdn.Microsoft.com/en-us/library/ms173147 (v = vs.80) .aspx

Convient également le commentaire sur la question: Quelle est la différence entre IEquatable et simplement remplacer Object.Equals ()?

14
Baz1nga

J'ai eu un problème similaire, mais heureusement, j'utilise déjà

using Newtonsoft.Json;

J'ai donc juste eu à le sérialiser en objet json puis à le comparer sous forme de chaîne.

var obj1Str = JsonConvert.SerializeObject(obj1);
var obj2Str = JsonConvert.SerializeObject(obj2);
Assert.Equal(obj1Str, obj2Str );
35
The Integrator

Je sais que c'est une vieille question, mais depuis que je suis tombé dessus, j'ai pensé que je peserais avec une nouvelle solution qui est disponible (au moins dans xunit 2.3.1 dans une solution .net Core 2.0).

Je ne sais pas quand il a été introduit, mais il existe maintenant une forme surchargée de .Equal Qui accepte une instance de IEqualityComparer<T> Comme troisième paramètre. Vous pouvez créer un comparateur personnalisé dans votre test unitaire sans polluer votre code avec.

Le code suivant peut être appelé comme ceci: Assert.Equal(expectedParameters, parameters, new CustomComparer<ParameterValue>());

XUnit semble nativement arrêter le traitement d'un test dès qu'un échec est rencontré, donc lancer un nouveau EqualException depuis notre comparateur semble être en ligne avec la façon dont XUnit fonctionne hors de la boîte.

public class CustomComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T expected, T actual)
    {
        var props = typeof(T).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
        foreach (var prop in props)
        {
            var expectedValue = prop.GetValue(expected, null);
            var actualValue = prop.GetValue(actual, null);
            if (!expectedValue.Equals(actualValue))
            {
                throw new EqualException($"A value of \"{expectedValue}\" for property \"{prop.Name}\"",
                    $"A value of \"{actualValue}\" for property \"{prop.Name}\"");
            }
        }

        return true;
    }

    public int GetHashCode(T parameterValue)
    {
        return Tuple.Create(parameterValue).GetHashCode();
    }
}

Edit: j'ai trouvé que la comparaison des valeurs réelles et attendues avec != N'était pas efficace pour certains types (je suis sûr qu'il y a une meilleure explication impliquant la différence entre les types de référence et les types de valeur, mais ce n'est pas pour aujourd'hui). J'ai mis à jour le code pour utiliser la méthode .Equals pour comparer les deux valeurs et cela semble fonctionner beaucoup mieux.

6
Engineer_Andrew

Il existe des packages NuGet qui le font pour vous. Voici deux exemples que j'utilise personnellement.

  1. DeepEqual :

    object1.ShouldDeepEqual(object2);
    
  2. ExpectedObjects :

    [Fact]
    public void RetrievingACustomer_ShouldReturnTheExpectedCustomer()
    {
      // Arrange
      var expectedCustomer = new Customer
      {
        FirstName = "Silence",
        LastName = "Dogood",
        Address = new Address
        {
          AddressLineOne = "The New-England Courant",
          AddressLineTwo = "3 Queen Street",
          City = "Boston",
          State = "MA",
          PostalCode = "02114"
        }                                            
      }.ToExpectedObject();
    
    
      // Act
      var actualCustomer = new CustomerService().GetCustomerByName("Silence", "Dogood");
    
      // Assert
      expectedCustomer.ShouldEqual(actualCustomer);
    }
    
6
maracuja-juice

La bibliothèque FluentAssertions a une logique de comparaison assez puissante à l'intérieur.

myObject.ShouldBeEquivalentTo(new { SomeProperty = "abc", SomeOtherProperty = 23 });

Vous pouvez même l'utiliser pour affirmer une partie de "myObject". Cependant, cela peut ne pas vous aider avec les champs privés.

0
Adrian Petrescu