I'm in the middle of covering some of our service classes with unit tests and I have managed to isolate/fake the dbcontext using NSubstitute (following this guide). I have some tests done and working, and things seemed to be alright, but now I can't find an entity I added to the context.
The test code is pretty straightforward:
[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);
}
The FakeContextBuilder
is a helper class I made for setting up the context (similar methods for other entities):
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;
}
}
Service method:
public void CreateStore(int accountID, int someProperty, string someOtherProperty)
{
var account = _context.Accounts.Find(accountID);
account.Stores.Add(new Store(someProperty, someOtherProperty));
}
On the Accounts.Find()
row I get null
instead of the expected account instance. If I add a breakpoint and look at the context I see that "enumerate results" on Accounts yields no results, but I can see that the provider and enumerator etc are set correctly in non-public members. The fake context builder also works fine in other tests, so my guess is that this is related to the Find() method.
EDIT: I have now confirmed that the Find() method is the culprit since the test passes when doing this instead:
var account = _context.Accounts.Single(act => act.Id == 10);
I still want to use Find() for caching purposes and so on. Can this be configured in the test code somehow? Would hate to mess up the production code for this, since it's really a simple operation.