So I'm trying to test out a function and it requires the use of a FindAsync function. i've boiled the code down to this example. When I run it, I get a NullReferenceExcetption from the FindAsync method. I believe that this is caused by an internal error in the arrangement of the MockSet.
[TestMethod()]
public
async Task _ShipmentController_DetailsReturnsHttpNotFoundOnNullShipments()
{
//Arrange
var shipments =
new
List<ShipmentPlayer>
{
new
ShipmentPlayer(){ShipmentID = 0},
}.AsQueryable();
var mockSet = createMockShipmentPlayerDB(shipments);
var mockContext = Mock.Create<ExportAttempt4Entities>();
Mock.Arrange(() => mockContext.ShipmentPlayersGroup).Returns(mockSet);
//Act
ShipmentPlayer query = await mockContext.FindAsync(0);
//Assert
Assert.IsNotNull(query);
}
Async set creation method:
private
DbSet<ShipmentPlayer> createMockShipmentPlayerDB(IQueryable<ShipmentPlayer> chks)
{
/*
* This function is a helper to create ASync databases.
* To modify this for your DB, change the Generics (<T>)
* to your prefferend generic
*/
var mockSet = Mock.Create<DbSet<ShipmentPlayer>>();
Mock.Arrange(() => ((IDbAsyncEnumerable<ShipmentPlayer>)mockSet).GetAsyncEnumerator())
.Returns(
new
TestDbAsyncEnumerator<ShipmentPlayer>(chks.GetEnumerator()));
Mock.Arrange(() => ((IQueryable<ShipmentPlayer>)mockSet).Provider)
.Returns(
new
TestDbAsyncQueryProvider<ShipmentPlayer>(chks.Provider));
Mock.Arrange(() => ((IQueryable<ShipmentPlayer>)mockSet).Expression).Returns(chks.Expression);
Mock.Arrange(() => ((IQueryable<ShipmentPlayer>)mockSet).ElementType).Returns(chks.ElementType);
Mock.Arrange(() => ((IQueryable<ShipmentPlayer>)mockSet).GetEnumerator()).Returns(chks.GetEnumerator());
return
mockSet;
}
Async Database info:
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; }
}
}
I found a possible solution in the Moq framework but I can't really translate to Just Mock. The idea is that you would place the following block of code in the set creation function:
mockSet.Setup(t => t.FindAsync(It.IsAny<
int
>())).Returns(Task.FromResult(chks));
I've only been using Just Mock for a few days now, so it might just a be a fundamental issue that I'm missing.