我正在嘲笑DbContext
进行单元测试,当您在数据库中保存更改时,您添加的实例会拉出数据库标识列分配的新ID,有没有办法模拟这种行为?,I真的不知道从哪里开始。
var acc = new Account {Name = "A New Account"};
_db.Accounts.Add(acc);
_db.SaveChanges();
Assert.IsTrue(acc.Id > 0);
哪里
public class TestDbContext : IEntities
{
public DbSet<Instance> Accounts { get; set; } = new MockDbSet<Accounts>();
}
并且
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace ControliApiTests.Data
{
public class MockDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T> where T : class
{
readonly ObservableCollection<T> _data;
readonly IQueryable _queryable;
public MockDbSet()
{
_data = new ObservableCollection<T>();
_queryable = _data.AsQueryable();
}
public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from MockDbSet<T> and override Find");
}
public Task<T> FindAsync(CancellationToken cancellationToken, params object[] keyValues)
{
throw new NotImplementedException();
}
public override T Add(T item)
{
_data.Add(item);
return item;
}
public override IEnumerable<T> AddRange(IEnumerable<T> entities)
{
var addRange = entities as T[] ?? entities.ToArray();
foreach (var entity in addRange)
{
_data.Add(entity);
}
return addRange;
}
public override T Remove(T item)
{
_data.Remove(item);
return item;
}
public override T Attach(T item)
{
_data.Add(item);
return item;
}
public override T Create()
{
return Activator.CreateInstance<T>();
}
public override TDerivedEntity Create<TDerivedEntity>()
{
return Activator.CreateInstance<TDerivedEntity>();
}
public override ObservableCollection<T> Local
{
get { return _data; }
}
Type IQueryable.ElementType
{
get { return _queryable.ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _queryable.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return new AsyncQueryProviderWrapper<T>(_queryable.Provider); }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
internal class AsyncQueryProviderWrapper<T> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal AsyncQueryProviderWrapper(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new AsyncEnumerableQuery<T>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new AsyncEnumerableQuery<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));
}
}
public class AsyncEnumerableQuery<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>
{
public AsyncEnumerableQuery(IEnumerable<T> enumerable) : base(enumerable)
{
}
public AsyncEnumerableQuery(Expression expression) : base(expression)
{
}
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new AsyncEnumeratorWrapper<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
}
public class AsyncEnumeratorWrapper<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumeratorWrapper(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; }
}
}
}
答案 0 :(得分:2)
如果你定义
private static int IdentityCounter = 1;
在模拟实现中并为每个添加的项增加一个,只要应用域存在,您将获得一个不会重置的递增值。
如果您的测试允许多线程添加,请使用Interlocked.Increment更新计数器。
请注意,您当前的实现不要求对象具有Id属性。如果测试中的所有类都具有此类属性,则可以定义要使用的接口,而不是允许class
的任何类。
public interface DbEntity
{
int Id { get; set; }
}
public class MockDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T> where T : DbEntity
通过这种更改,您的Add实现可能看起来像
public override T Add(T item)
{
item.Id = IdentityCounter++; // Or use Interlocked.Increment to support multithreading
_data.Add(item);
return item;
}
答案 1 :(得分:-1)
如果您不想使用界面,可以使用反射和扩展方法来获取并评估ID
.*
grep