Question

Je crée un IDbSet simulé pour permettre, entre autres, les tests unitaires des classes de framework d'entité.

Cependant, j'ai vraiment du mal à détecter les changements, ou même à comprendre comment le faire.Voici mes cours jusqu'à présent...

public interface IReportContext
{
    IDbSet<Report> Reports {get;}
    public int SaveChanges();
}

public class MockReportContext : IReportContext
{
    IDbSet<Report> Reports {get;}

    public int SaveChanges()
    {
        //Need to detect changes here???
    }

    public MockReportContext()
    {
       Reports = new MockDbSet<Report>();
    }
}

public class MockDbSet<T> : IDbSet<T>
{
    readonly ObservableCollection<T> _data;
    readonly IQueryable _query;

    public FakeDbSet()
    {
        _data = new ObservableCollection<T>();
        _query = _data.AsQueryable();
    }

    public FakeDbSet(ObservableCollection<T> data)
    {
        _data = data;
        _query = _data.AsQueryable();
    }

    public virtual T Find(params object[] keyValues)
    {
        throw new NotImplementedException();
    }

    public T Add(T item)
    {
        _data.Add(item);
        return item;
    }

    public T Remove(T item)
    {
        _data.Remove(item);
        return item;
    }

    public T Attach(T item)
    {
        _data.Add(item);
        return item;
    }

    public T Detach(T item)
    {
        _data.Remove(item);
        return item;
    }

    public T Create()
    {
        return Activator.CreateInstance<T>();
    }

    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
    {
        return Activator.CreateInstance<TDerivedEntity>();
    }

    public ObservableCollection<T> Local
    {
        get { return _data; }
    }

    Type IQueryable.ElementType
    {
        get { return _query.ElementType; }
    }

    System.Linq.Expressions.Expression IQueryable.Expression
    {
        get { return _query.Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _query.Provider; }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return _data.GetEnumerator();
    }
}

Cela fonctionne très bien pour ajouter, supprimer et récupérer des entités.Cependant, lorsque j'essaie ce qui suit :

IReportContext context = new MockReportContext();
context.Reports.Add(new Report()); //Works
Report report = context.Reports.First(); //Works
report.Message = "Hello World!";
context.SaveChanges(); //Does nothing

Comment se fait-il que MockReportContext puisse savoir que l'objet de rapport qu'il a renvoyé a changé ??Je sais que l'utilisation du framework d'entité fait cela, donc cela doit être possible, mais je n'ai aucune idée de comment...

Était-ce utile?

La solution

Je pense que vous êtes principalement là, mais je suggère d'utiliser un framework moqueur comme Moq (ma préférence personnelle) ou Des moqueries de rhinocéros se moquer du IReportContext pour vos tests unitaires, au lieu de vous donner la peine de créer un Faux classe comme MockReportContext.(D'accord, apprendre un framework moqueur implique quelques problèmes, mais cela vous évitera bien des corvées de fausse classe plus tard.)

Je suppose que vous testez unitairement le code qui dépend du IReportContext, donc vous n'avez rien à faire à l'intérieur SaveChanges(), il vous suffit d'affirmer que votre code a bien appelé SaveChanges() en interne si c'était censé le faire.

Voici un bon aperçu d'utiliser Moq avec les classes DbContext / DbSet dérivées d'Entity Framework.

Dans l'aperçu lié ci-dessus, si le test unitaire à la fin testait une méthode qui appelle en interne SaveChanges(), il pourrait en outre vérifier que SaveChanges() a bien été appelé par votre méthode avec la ligne :

dc.Verify(db => db.SaveChanges());

Vous pouvez également le faire avec votre MockReportContext classe en définissant une propriété latérale sur True à l'intérieur du SaveChanges() classe et la vérifier à la fin de votre test unitaire, mais un framework moqueur est beaucoup plus flexible et évitera d'avoir à écrire des classes supplémentaires pour les tests unitaires.

Si vous souhaitez éviter d'utiliser un framework moqueur, voici comment faire avec des contrefaçons.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top