DbSet mock, no results while calling ToList secondly - c#

I'm trying to mock DbContext and DbSet. This works for my previous unit tests, but problem occurs while my code was calling ToList method on DbSet second time.
First dbSet.ToList() returns mocked results.
Second one returns 0 elements;
var queryableData = new List<string>{ "a", "b", "c" }.AsQueryable();
var mockDbSet = new Mock<DbSet<string>>();
var q = mockDbSet.As<IQueryable<string>>();
q.Setup(m => m.Provider).Returns(queryableData.Provider);
q.Setup(m => m.Expression).Returns(queryableData.Expression);
q.Setup(m => m.ElementType).Returns(queryableData.ElementType);
q.Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
DbSet<string> dbset = mockDbSet.Object;
IQueryable<string> query = dbset;
//RESULTS: abc
var a1 = dbset.ToList();
foreach (var a in a1)
Console.Write(a);
//NO RESULTS
var a2 = dbset.ToList();
foreach (var a in a2)
Console.Write(a);

You return the very same enumerator instance upon each call to GetEnumerator. When it enumerates once, it is done, EF doesn't call its Reset method, rather it asks for a new enumerator.
But you return the one that just has yielded all elements and yields no more.
Instead, return a function that returns the enumerator, that will return a new enumerator each time you ask for it.
q.Setup(m => m.GetEnumerator()).Returns( () => queryableData.GetEnumerator() );

I just wanted to added to Wiktor Zychla's answer my little part. If someone is looking for Async version of this mock (coming from this tutorial: http://msdn.microsoft.com/en-us/data/dn314429.aspx#async) then this is my modification to TestDbAsyncEnumerator<T> class:
internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestDbAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public TestDbAsyncEnumerator(Func<IEnumerator<T>> valueFunction)
{
_inner = valueFunction();
}
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; }
}
}
Then like Wiktor suggested you have to setup it with delegate so in case of async it would be like that:
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<Blog>(() => data.GetEnumerator()));
If someone wants source for that then here you go: https://github.com/kelostrada/EntityFrameworkWithMock.Test

I can't comment on Wiktor's post as I haven't got enough reputation, but i would like to add a little extra to Wiktor's answer.
The code
mockSet.Setup((m => m.GetEnumerator()).Returns(() => data.GetEnumerator())
Will fail if you give it a zero argument lambda like in the example(At least the version I am using).
Passing an argument that is never used will allow it to meet the signature requirement however.
mockSet.Setup((m => m.GetEnumerator()).Returns(x => data.GetEnumerator())
Will compile however, and works as expected.
And this also applies to Kelu's answer as well (Although he has added the lambda in the wrong place.
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(x => new TestDbAsyncEnumerator<Blog>(data.GetEnumerator()));
Not trying to nitpick answers here, i'm just adding because i made these mistakes myself :)

If you put a "Where" clause before the .ToList() call, the data should remain present.
var a1 = dbset.Where(m => m != null).ToList();
var a2 = dbset.Where(m => m != null).ToList();

Related

How to run a function when return value is void upon setup in Moq

So when there is a return value, I can do this in Moq
mockStudentRepository.Setup(m => m.Create(It.IsAny<IStudent>())).Returns<IStudent>(s =>
{
students.Add(s);
return 1;
});
so this lambda gets ran as the mock implementation of the repository.
How do I do this when a method returns void? When I try the same code, Returns is not available. I have something like this right now:
mockStudentRepository.Setup(m => m.Update(It.IsAny<IStudent>()));
I want to put a lambda that will run when Update is called much like the first code above. How can I do this?
I believe you are looking for the Callback extension.
mockStudentRepository
.Setup(m => m.Update(It.IsAny<IStudent>()))
.Callback<IStudent>(s => {
var student = students.Where(x => x.Id == s.Id).FirstOrDefault();
if(student != null) {
//...
}
});

Mock Linq `Any` predicate with Moq

I'm trying to mock AnyAsync method in my repository with below codes but repository always returns false.
The signature of AnyAsync is:
Task<bool> AnyAsync<TEntity>(Expression<Func<TEntiry, bool>> predicate)
I tried the following setups:
1:
mockCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some#one.com"))
.ReturnsAsync(true);
2:
Expression<Func<CustomerEntity, bool>> predicate = expr =>
expr.CustomerPerson.Email == "some#one.com";
mockCustomerRepository.Setup(r => r.AnyAsync(It.Is<Expression<Func<CustomerEntity, bool>>>
(criteria => criteria == predicate))).ReturnsAsync(true);
3:
mockCustomerRepository.Setup(r => r.AnyAsync(It.IsAny<Expression<Func<CustomerEntity, bool>>>()))
.ReturnsAsync(true);
My test:
public class Test
{
Mock<ICustomerRepository> mockCustomerRepository;
public Test()
{
mockCustomerRepository = new Mock<ICustomerRepository>();
}
[Fact]
public async Task CustomerTest()
{
var customer = ObjectFactory.CreateCustomer(email: "some#one.com");
var sut = new CustomerService(mockCustomerRepository.Object);
var result = await sut.ValidateCustomerAsync(customer);
.
.
.
}
}
My CustomerService.ValidateCustomerAsync method:
public async Task<OperationResult> ValidateCustomerAsync(CustomerEntity customer)
{
var errors = new List<ValidationResult>();
if (await _repository.AnyAsync(c => c.Email == customer.Email))
errors.Add(new ValidationResult("blah blah")));
I've also read this but it doesn't work too.
The following snippet shows the correct way to mock your AnyAsync method:
[TestMethod]
public async Task TestMethod1()
{
var fakeCustomerRepo = new Mock<ICustomerRepository>();
var foo = false;
fakeCustomerRepo.Setup(repository => repository.AnyAsync(It.IsAny<Expression<Func<CustomerEntity, bool>>>()))
.Callback<Expression<Func<CustomerEntity, bool>>>(
expression =>
{
var func = expression.Compile();
foo = func(new CustomerEntity() {Email = "foo#gmail.com"});
})
.Returns(() => Task.FromResult(foo));
var customer = new CustomerEntity() {Email = "foo#gmail.com"};
var result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsTrue(result);
customer = new CustomerEntity() { Email = "boo#gmail.com" };
result = await fakeCustomerRepo.Object.AnyAsync<CustomerEntity>(c => c.Email == customer.Email);
Assert.IsFalse(result);
}
using the above setup you can verify your predicate which is part of your unit behavior.
I think you're running into the difficulties of matching predicates. Funcs or expressions of Funcs use reference-equality, so just using == to compare the two instances isn't going to work. (As a general rule, if you can't get predicate1.Equals(predicate2) to return true, Moq's argument matchers aren't going to match.)
This is a little unorthodox, but I refer you to my answer to a similar question for FakeItEasy matchers, which in turn points you at a number of techniques for validating predicates.
All I can see that should cause this problem are two options:
1. The repository method does not come from an interface that you should mock to return the desired value, as it is not marked with virtual.
2. The types (TEntity) you use in method do not match when you are using the moq.
AnyAsync<TEntity>(Expression<Func<TEntity, bool>>
as you can setup for let's say MemberEntity and call the ValidateCustomerAsync with a CustomerEntity.
Maybe I am wrong but, but as far as I have read for methods that return only a Task, .Returns(Task.FromResult(default(object))) can and should be used.
So in your case it would be mocksCustomerRepository.Setup(r => r.AnyAsync(c => c.Email == "some#one.com")).Returns(Task.FromResult(true));

Conditionally Include and ThenInclude

As commonly known in EF-Core there is no Lazy loading. So that kind of means I'm forced to do my queries with some afterthought. So since I have to think, then i might as well try to do it properly.
I have a Fairly standard update query, but I thought hey, I don't always have to include the HeaderImage and PromoImage FK-objects. There should be a way to make that happen. But I can just not find a way to perform a Include at a later point. In-fact I would like to maybe include right before I actually do work on the object. That way i might be able to automate some of the eagerness.
ArticleContent ac = _ctx.ArticleContents
.Include(a=> a.Metadata)
.Include(a=> a.HeaderImage)
.Include(a=> a.PromoImage)
.Single(a => a.Id == model.BaseID);
ac.Title = model.Title;
ac.Ingress = model.Ingress;
ac.Body = model.Body;
ac.Footer = model.Footer;
if (model.HeaderImage != null)
{
ac.HeaderImage.FileURL = await StoreImage(model.HeaderImage, $"Header_{model.Title.Replace(" ", "_")}_{rand.Next()}");
}
if (model.PromoImage != null)
{
ac.PromoImage.FileURL = await StoreImage(model.PromoImage, $"Promo_{model.Title.Replace(" ", "_")}_{rand.Next()}");
}
ac.Metadata.EditedById = uId;
ac.Metadata.LastChangedTimestamp = DateTime.Now;
await _ctx.SaveChangesAsync();
EXTRA
To be clear, this is EF7 (Core), and im after a solution that allows me to add includes on demand, hopefully after the initial _ctx.ArticleContents.Include(a=> a.Metadata).Single(a => a.Id == model.BaseID).
I'm using something similar to Alexander Derck's solution. (Regarding the exception mentioned in the comments: ctx.ArticleContents.AsQueryable() should also work.)
For a couple of CRUD MVC sites I'm using a BaseAdminController. In the derived concrete Controllers I can add Includes dynamically. From the BaseAdminController:
// TModel: e.g. ArticleContent
private List<Expression<Func<TModel, object>>> includeIndexExpressionList = new List<Expression<Func<TModel, object>>>();
protected void AddIncludes(Expression<Func<TModel, object>> includeExpression)
{
includeIndexExpressionList.Add(includeExpression);
}
Later I saw that I need more flexibility, so I added a queryable. E.g. for ThenInclude().
private Func<IQueryable<TModel>, IQueryable<TModel>> IndexAdditionalQuery { get; set; }
protected void SetAdditionalQuery(Func<IQueryable<TModel>, IQueryable<TModel>> queryable)
{
IndexAdditionalQuery = queryable;
}
Here the Index action:
public virtual async Task<IActionResult> Index()
{
// dynamic include:
// dbset is for instance ctx.ArticleContents
var queryable = includeIndexExpressionList
.Aggregate(dbSet.AsQueryable(), (current, include) => current.Include(include));
if(IndexAdditionalQuery != null) queryable = IndexAdditionalQuery(queryable);
var list = await queryable.Take(100).AsNoTracking().ToListAsync();
var viewModelList = list.Map<IList<TModel>, IList<TViewModel>>();
return View(viewModelList);
}
In the concrete Controller I use:
AddIncludes(e => e.EventCategory);
SetAdditionalQuery(q => q
.Include(e => e.Event2Locations)
.ThenInclude(j => j.Location));
I would create a method to fetch the data which takes the properties to include as expressions:
static ArticleContent GetArticleContent(int ID,
params Expression<Func<ArticleContent, object>>[] includes)
{
using(var ctx = new MyContext())
{
var acQuery = _ctx.ArticleContents.Include(a=> a.Metadata);
foreach(var include in includes)
acQuery = acQuery.Include(include);
return acQuery.Single(a => a.Id == model.BaseID);
}
}
And then in main method:
var ac = GetArticleContent(3, a => a.HeaderImage, a => a.PromoImage);

C# Moq Entity Framework 6 Data Context Add Operation

I want to test that a method adds a record to a DBSet under a certain condition:
public static void AddTriggeredInternalTransactions(IDataContext dc, ExternalTransaction transaction)
{
if (transaction [meets condition A])
dc.InternalTransactions.CreateInverseTransaction(transaction);
// do other stuff under other conditions
}
private static void CreateInverseTransaction(this IDbSet<InternalTransaction> transactions, ExternalTransaction from)
{
var internalTransaction = transactions.Create();
from.CopyToInternalTransaction(internalTransaction);
transactions.Add(internalTransaction);
}
Now, I already have tests for CopyToInternalTransaction(). I just need to call AddTriggeredInternalTransactions() and verify that [condition A] results in the new record being added).
I started with http://msdn.microsoft.com/en-us/data/dn314429.aspx, then used other Google and StackOverflow searches. Before tackling my "real" test, I'm trying to do a simple test just to verify whether a record has been added to a dataset, but I'm stuck on this. Can anyone point out my flaw(s)?
var internals = new Mock<DbSet<InternalTransaction>>();
var theData = new List<InternalTransaction>().AsQueryable();
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.Provider).Returns(theData.Provider);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.Expression).Returns(theData.Expression);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.ElementType).Returns(theData.ElementType);
internals.As<IQueryable<InternalTransaction>>().Setup(m => m.GetEnumerator()).Returns(theData.GetEnumerator());
var mockDC = new Mock<IDataContext>();
mockDC.Setup(q => q.InternalTransactions).Returns(internals.Object);
mockDC.Setup(q => q.InternalTransactions.Create()).Returns(new InternalTransaction());
mockDC.Setup(q => q.InternalTransactions.Add(It.IsAny<InternalTransaction>()));
var it = mockDC.Object.InternalTransactions.Create();
it.Id = "123";
mockDC.Object.InternalTransactions.Add(it);
internals.Verify(e => e.Add(It.Is<InternalTransaction>(d => d.Id == "123")), Times.Once());
//or: Assert.Equal(1, mockDC.Object.InternalTransactions.Count());
This test fails with: Expected invocation on the mock once, but was 0 times: e => e.Add(It.Is(d => d.Id == "123")) No setups configured. No invocations performed.
The Assert statement, if used instead, fails with a NotImplementedException: "The member IQueryable.Provider has not been implemented on type DbSet~1Proxy_1 which inherits from DbSet1. Test doubles for DbSet1 must provide implementations of methods and properties that are used."
After comments by Adam and Stuart plus further experimentation, I was able to reduce my test case to the following working test case:
var internals = new Mock<DbSet<InternalTransaction>>();
var mockDC = new Mock<IDataContext>();
mockDC.Setup(q => q.InternalTransactions).Returns(internals.Object);
internals.Setup(q => q.Create()).Returns(new InternalTransaction());
var transaction = new ExternalTransaction { [set criteria for Condition A] };
SomeBusinessObject.AddTriggeredInternalTransactions(mockDC.Object, transaction);
// verify the Add method was executed exactly once
internals.Verify(e => e.Add(It.IsAny<InternalTransaction>()), Times.Once());

How do I return a different value from a stub based on a lambda argument

I have the following sample test code
public Stage Test(Stage Stage)
{
var StartStage = StageRepository.Single(x => x.Order == 1);
var EndStage = StageRepository.Single(x => x.Order == 5);
var ErrorStage = StageRepository.Single(x => x.Name == "Error");
if (Stage == StartStage)
{
return EndStage;
}
else
{
return ErrorStage;
}
}
And I am trying to test it using the following unit test
[TestMethod]
public void XXXTest()
{
//// Arrange
var AutoMocker = new RhinoAutoMocker<StageService>(MockMode.AAA);
MockRepository mockRepository = new MockRepository();
var MockStageRepository = AutoMocker.Get<IRepository<Stage>>();
Stage StartStage = mockRepository.Stub<Stage>();
StartStage.Order = 1;
Stage EndStage = mockRepository.Stub<Stage>();
EndStage.Order = 5;
Stage ErrorStage = mockRepository.Stub<Stage>();
ErrorStage.Name = "Error";
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> StartParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(StartParam)))
.Return(StartStage);
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> EndParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(EndParam)))
.Return(EndStage);
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> ErrorParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(ErrorParam)))
.Return(ErrorStage);
StageService StageService = AutoMocker.ClassUnderTest;
//Act
var ReturnStage = StageService.Test(StartStage);
//Assert
Assert.AreEqual(ReturnStage, EndStage);
}
However this is not working as it is not returning anything when I call StageRepository.Single(). If I change the stub code to ignore the argument then it does return something but it will be the same object returned for each call to Single() which I don't want.
Is it possible to configure RhinoMocks in such a way as to return different objects from a stub depending on the lambda that is passed into it?
I think the root of your problem is that equality on the Expression<Func<T,U>> type is performed by reference rather than value. That means your telling Rhino Mocks to look for instances of expressions created in the test rather than the ones created in the code your testing.
Two possible approaches come to mind:
One would be to provide a way to pass the lambda expressions in to the Stage class from the test, so that when the argument checks happen they are working against the same instances.
Maybe something like:
internal void SetStartStage(Expression<Func<Entities.Stage,bool>> predicate)
{
...
}
The inverse of this would also work, i.e. provide the Expression objects as fields/properties that can be accessed by you're test, and then use those when setting up your mock:
internal Expression<Func<Entities.State,bool>> StartStagePredicate
{
get{ return x => x.Order == 1; }
}
Another option would be to use the Matches method on Args to see if the argument checks the Stage object state correctly. This would require creating some Stage objects in your test that would match the criteria:
var startStageTester = new Stage { Order = 1 };
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(startStageTester)))
.Return(StartStage);
The call to Compile() is a little jarring, but since you're dealing with an Expression and not a straight-up lambda, you've got to compile it in order to evaluate it.
Now, if a Stage is something that is hard to create, then you may need to create a Mock/Stub of one (or use you're StartStage) and have it return 1 from the Order property (in the case of the StartStage anyway).
There are probably some others I'm not thinking of at the moment as well.
IF the linq condition is not important, I would propose to match it as any, something like this
repository.Stub(x => x.Find(Arg<System.Linq.Expressions.Expression<Func<Entity, bool>>>.Is.Anything)).Return(entitiesList.AsQueryable());
Hope this help.
Thanks for that. That worked a treat. The one thing that I was missing was the Compile method on an ExpressionTree. There is a small bug in your sample code (you use x twice). For completeness here is the working code.
MockStageRepository2
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(StartStage2))))
.Return(StartStage2);

Categories