Heim  >  Artikel  >  Backend-Entwicklung  >  C# entkoppelt EntityFramework für Unit-Tests

C# entkoppelt EntityFramework für Unit-Tests

黄舟
黄舟Original
2017-02-28 11:18:242043Durchsuche

1. Zunächst muss das abstrakte Verhalten des EF-Repositorys in der Schnittstelle erwähnt werden.

Zum Beispiel:

public interface IXXXContext : IDisposable
    {
        IXXXContext NewInstance();
// db sets
        DbSet<AAABBB> aaa { get; set; }
...
// common 
Database Database { get; }
        DbContextConfiguration Configuration { get; }
        int SaveChanges();


        Task<int> SaveChangesAsync();


	// store pros
...
        IStorePro1 StorePro1 { get; }
	...
}


Dann können Sie DataContext und TestDataContext verwenden, um diese Schnittstelle zu implementieren. Unter anderem wird TestDataContext in UT verwendet und DataContext wird automatisch generiert.

TestDataContext erfordert außerdem die folgenden Klassen für die Simulation.

 public class TestDbSet<TEntity> : DbSet<TEntity>, IQueryable, IEnumerable<TEntity>, IDbAsyncEnumerable<TEntity>
         where TEntity : class
    {
        ObservableCollection<TEntity> _data;
        IQueryable _query;


        public TestDbSet()
        {
            _data = new ObservableCollection<TEntity>();
            _query = _data.AsQueryable();
        }


        public override TEntity Add(TEntity item)
        {
            _data.Add(item);
            return item;
        }


        public override TEntity Remove(TEntity item)
        {
            _data.Remove(item);
            return item;
        }


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


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


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


        public override ObservableCollection<TEntity> Local
        {
            get { return _data; }
        }


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


        Expression IQueryable.Expression
        {
            get { return _query.Expression; }
        }


        IQueryProvider IQueryable.Provider
        {
            get { return new TestDbAsyncQueryProvider<TEntity>(_query.Provider); }
        }


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


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


        IDbAsyncEnumerator<TEntity> IDbAsyncEnumerable<TEntity>.GetAsyncEnumerator()
        {
            return new TestDbAsyncEnumerator<TEntity>(_data.GetEnumerator());
        }
    }


    internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
    {
        private readonly IQueryProvider _inner;


        internal TestDbAsyncQueryProvider(IQueryProvider inner)
        {
            _inner = inner;
        }


        public IQueryable CreateQuery(Expression expression)
        {
            return new TestDbAsyncEnumerable<TEntity>(expression);
        }


        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new TestDbAsyncEnumerable<TElement>(expression);
        }


        public object Execute(Expression expression)
        {
            return _inner.Execute(expression);
        }


        public TResult Execute<TResult>(Expression expression)
        {
            return _inner.Execute<TResult>(expression);
        }


        public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute(expression));
        }


        public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute<TResult>(expression));
        }
    }


    internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
    {
        public TestDbAsyncEnumerable(IEnumerable<T> enumerable)
            : base(enumerable)
        { }


        public TestDbAsyncEnumerable(Expression expression)
            : base(expression)
        { }


        public IDbAsyncEnumerator<T> GetAsyncEnumerator()
        {
            return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
        }


        IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
        {
            return GetAsyncEnumerator();
        }


        IQueryProvider IQueryable.Provider
        {
            get { return new TestDbAsyncQueryProvider<T>(this); }
        }
    }


    internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
    {
        private readonly IEnumerator<T> _inner;


        public TestDbAsyncEnumerator(IEnumerator<T> inner)
        {
            _inner = inner;
        }


        public void Dispose()
        {
            _inner.Dispose();
        }


        public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
        {
            return Task.FromResult(_inner.MoveNext());
        }


        public T Current
        {
            get { return _inner.Current; }
        }


        object IDbAsyncEnumerator.Current
        {
            get { return Current; }
        }
    }


Verwendungsbeispiel:

[TestMethod]
        public void TestMethod1()
        {
            var mockSet = new Mock<DbSet<BLACKLISTED_TICKET>>();
            var mockContext = new Mock<TicketDataContextTest>();
            mockContext.Setup(m => m.BLACKLISTED_TICKET).Returns(new TestDbSet<BLACKLISTED_TICKET>());


            var context = mockContext.Object;


            context.BLACKLISTED_TICKET.Add(new BLACKLISTED_TICKET()
            {
                TicketNumber = "aaa",
                CreatedDateTime = DateTime.Now,
                Id = 1,
                ModifiedDateTime = DateTime.Now,
                STATUS = "1"
            });


            Assert.IsTrue(context.BLACKLISTED_TICKET.First().Id == 1);
        }

Wenn eine gespeicherte Prozedur verwendet wird, müssen Sie zusätzlich die Schnittstelle der gespeicherten Prozedur definieren Verfahren.
Zum Beispiel:

IStorePro {
...
}


StorePro : IStorePro{
...
}


StoreProFake: IStorePro{


}

Dann ist IDataContext für die Rückgabe der Instanz der gespeicherten Prozedur verantwortlich

IDataContext{
	...
	IStorePro GetStorePro();
	...
}

Das Obige ist der Inhalt der C#-Entkopplung EntityFramework für Unit-Tests und mehr Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn