This is a migrated thread and some comments may be shown as answers.

Unable to perform Async Actions on Mock

1 Answer 355 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Bryon
Top achievements
Rank 1
Bryon asked on 09 Jun 2014, 06:10 PM

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.

1 Answer, 1 is accepted

Sort by
0
Kaloyan
Telerik team
answered on 12 Jun 2014, 01:18 PM
Hi Bryon,

I am happy that you are interested in our product.

About the issue you are experiencing, the Moq line you have posted should be fully supported in JustMock, with the following syntax:
Mock.Arrange(() => mockSet.FindAsync(Arg.AnyInt)).Returns(Task.FromResult(chks));

However, in your test I see that you are acting on a mocked object (mockContext). And as the default mock behavior in JustMock is RecursiveLoose, it is normal for the FindAsync method to return a non-null object, no matter the arrangements on the mockSet. In other words, written like this the test does not execute the original FindAsync logic. What I would suggest is to use a partial mock for the ExportAttempt4Entitiese class, like this:
[TestMethod()]
public async Task _ShipmentController_DetailsReturnsHttpNotFoundOnNullShipments()
{
    //Arrange
    var shipments = new List<ShipmentPlayer>
    {
        new ShipmentPlayer(){ShipmentID = 0},
    }.AsQueryable();
    var mockSet = createMockShipmentPlayerDB(shipments);
    var mockContext = new ExportAttempt4Entities();
    Mock.Arrange(() => mockContext.ShipmentPlayersGroup).Returns(mockSet);
    //Act
    ShipmentPlayer query = await mockContext.FindAsync(0);
    //Assert
    Assert.IsNotNull(query);
  
}

I hope this helps. Please, do not hesitate to write back if you need further assistance or you have more questions.

Regards,
Kaloyan
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
Tags
General Discussions
Asked by
Bryon
Top achievements
Rank 1
Answers by
Kaloyan
Telerik team
Share this question
or