我正在用单元测试覆盖我们的一些服务类,并且设法使用NSubstitute隔离/伪造dbcontext(遵循this指南)。我有一些测试已经完成并且正在工作,事情似乎没有问题,但是现在我找不到我添加到上下文中的实体。EF 6假数据库上下文,找不到实体
测试代码是非常简单的:
[Fact]
public void CreateStore_GivenAccount_AccountIsAssignedTheStore()
{
const int accountId = 10;
var account = new Account {Id = accountId};
var fakeContext = new FakeContextBuilder()
.WithAccounts(account)
.Build();
var service = new Service(fakeContext);
const int someProperty = 0;
const string someOtherProperty = "blabla";
service.CreateStore(accountId, someProperty, someOtherProperty);
var storeWasAdded = account.Stores
.Any(store =>
store.SomeProperty == someProperty &&
store.SomeOtherProperty == someOtherProperty);
Assert.True(storeWasAdded);
}
的FakeContextBuilder
是一个辅助I类用于建立上下文(对于其它实体的类似方法)制备:
public class FakeContextBuilder
{
private DbSet<Account> _accountTable;
private static DbSet<TEntity> SetUpFakeTable<TEntity>(params TEntity[] entities) where TEntity : class
{
var fakeTable = Substitute.For<DbSet<TEntity>, IQueryable<TEntity>>() as IQueryable<TEntity>;
var table = entities.AsQueryable();
fakeTable.Provider.Returns(table.Provider);
fakeTable.Expression.Returns(table.Expression);
fakeTable.ElementType.Returns(table.ElementType);
fakeTable.GetEnumerator().Returns(table.GetEnumerator());
return (DbSet<TEntity>) fakeTable;
}
public Context Build()
{
var context = Substitute.For<Context>();
context.Accounts.Returns(_accountTable);
return context;
}
public FakeContextBuilder WithAccounts(params Account[] accounts)
{
_accountTable = SetUpFakeTable(accounts);
return this;
}
}
服务方法:
public void CreateStore(int accountID, int someProperty, string someOtherProperty)
{
var account = _context.Accounts.Find(accountID);
account.Stores.Add(new Store(someProperty, someOtherProperty));
}
在Accounts.Find()
行我得到null
而不是预期的帐户实例。如果我添加一个断点并查看上下文,我发现在Accounts上“枚举结果”不会产生任何结果,但我可以看到提供程序和枚举程序等在非公共成员中正确设置。虚假的上下文构建器在其他测试中也能正常工作,所以我的猜测是这与Find()方法有关。
编辑:我现在已经证实,find()方法是罪魁祸首,因为这样做的时候,而不是测试通过:
var account = _context.Accounts.Single(act => act.Id == 10);
我还是想用find()方法用于高速缓存的目的等。可以在测试代码中以某种方式进行配置吗?会讨厌为此弄乱生产代码,因为这实际上是一个简单的操作。
这似乎是问题的事实,DbSet .Find()是'virtual',所以NSubstitute是使用空的实现覆盖它而产生。将进一步调查。 –
kai