简体   繁体   中英

Strange failure in Nunit test with NHibernate

running a simple test with NUnit and FluentAssertion i have this messagge for failure:

Expected object to be 

Gedi.Domain.Object.Entity.Persona
{
   Annullato = False
   Descrizione = "Persona1"
   Id = 1
}, but found 

Gedi.Domain.Object.Entity.Persona
{
   Annullato = False
   Descrizione = "Persona1"
   Id = 1
}.

but I do not see differences. which may be the cause of failure?

this is the test method

public void CanSaveAndLoadDocumento()
    {
        //Arrange
        Documento documentoTarget = new Documento();
        Documento documentoActual;

        documentoTarget.Id = fixture.Create<int>();                 

        // Act
        using (IUnitOfWork uow = new UnitOfWork())
        {
            uow.Start();
            documentoTarget.Persona = uow.ServiceRepositoryFor<Persona>().GetById(1);
            uow.DocumentoRepository.Create(documentoTarget);
            uow.Commit();
            uow.CloseConnection();

            uow.Start();
            documentoActual = uow.DocumentoRepository.GetById(documentoTarget.Id);          
            uow.CloseConnection();
        }

        //Assert
        documentoActual.Persona.Should().Be(documentoTarget.Persona);

    }

Persona with ID = 1 is handwritten by me directly in database

this is the base repository i use with NHibernate

public abstract class RepositoryBase<TEntity, TKey> : IDisposable
    where TEntity : class, IKeyedEntity<TKey>
    where TKey : struct
{
    protected ISession _session;
    public RepositoryBase(ISession session)
    {
        _session = session;         
    }       
    public void Create(TEntity entity)
    {
        _session.SaveOrUpdate(entity);
    }       
    public TEntity GetById(TKey id)
    {
        return _session.Get<TEntity>(id);
    }
}

public class DocumentoRepository : RepositoryBase<Documento, int>
{
    public DocumentoRepository(ISession session)
        : base(session)
    {
    }
}

Reason is simple - DocumentoRepository.GetById(documentoTarget.Id) creates new instance of Persona entity instead of returning cached instance. Fluent assertions compares both entities by reference, and you have assertion failure.

You can implement Equals and GetHashCode for your Persona class. Or use ShouldBeEquivlentTo for asserting object graph equivalence:

documentoActual.Persona.ShouldBeEquivlentTo(documentoTarget.Persona);

better version: in this way two object are equals if all properties are equals

public abstract class EquatableObject<TObject>: IEquatable<TObject>
    where TObject : class   
{
    protected EquatableObject()
    {           
    }

    public override int GetHashCode()
    {
        IEnumerable<FieldInfo> fields = GetFields();
        int startValue = 17;
        int multiplier = 59;
        int hashCode = startValue;

        foreach (FieldInfo field in fields)
        {
            object value = field.GetValue(this);
            if (value != null)
                hashCode = hashCode * multiplier + value.GetHashCode();
        }
        return hashCode;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        TObject other = obj as TObject;

        return Equals(other);

    }

    public virtual bool Equals(TObject other)
    {
        if (other == null)
            return false;

        Type t = GetType();
        Type otherType = other.GetType();

        if (t != otherType)
            return false;

        FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        foreach (FieldInfo field in fields)
        {
            object value1 = field.GetValue(other);
            object value2 = field.GetValue(this);

            if (value1 == null)
            {
                if (value2 != null)
                    return false;
            }
            else if (!value1.Equals(value2))
                return false;
        }
        return true;

    }

    private IEnumerable<FieldInfo> GetFields()
    {
        Type t = GetType();
        List<FieldInfo> fields = new List<FieldInfo>();
        while (t != typeof(object))
        {
            fields.AddRange(t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public));

            t = t.BaseType;
        }
        return fields;
    }
}

OLD

Solved adding

public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        T other = obj as T;

        return Equals(other);

    }

to my class

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM