Mocking FindAsync method - c#

I mocked FindAsync by the following code:
var brands = new Mock<DbSet<Brand>>();
ConfigureTheDbSet(brands, brandData);
brands.Setup(b => b.FindAsync(It.IsAny<object[]>())) //substitution of the .SelectAsync(id) method
.Returns<object[]>(ids => brands.Object.FirstOrDefaultAsync(b => b.BrandId == (int) ids[0]));
and it had been working correctly until I added mocking for AsNoTracking to context:
var mockContext = new Mock<ReportDbContext>();
mockContext.Setup(m => m.Set<Brand>()).Returns(brands.Object);
mockContext.Setup(m => m.Set<Brand>().AsNoTracking()).Returns(brands.Object);
And FindAsync returns null. To make it work i added the following mocking:
mockContext.Setup(m => m.Set<Brand>().FindAsync(It.IsAny<object[]>()))
.Returns<object[]>(async d => await brands.Object.FindAsync(d));
Anybody have a clue why this is happening?

IMO, you should be mocking interfaces, for example IBrandRepository. Otherwise whats the point of mocking? - you could just create an instance of your class, call FindAsync() and assert the result as usual..
Here is how I use Moq with interfaces, for example a repo interface;
// arrange
var mockRepo = new Mock<IBrandRepository>();
mockRepo.Setup(o => o.FindAsync(It.IsAny<string>())).ReturnsAsync(new Brand[] { ... });
var someClass = new SomeClass(IBrandRepository); // someClass that use IBrandRepository
// act
string search = "brand1 brand2"; // what the user searches for
var results = someClass.FindBrands(searchText) // internally calls IBrandRepository.FindAsync()
// assert
// Assert.AreEqual(results.Count(), ...

Dimitry, I know that it's been a couple of years. I just had the same issue and this is what I did to get it to work
this.mocContext.Setup(x => x.Company.FindAsync(It.IsAny<string>
())).Returns(Task.FromResult(this.GetCompanyList().SingleOrDefault(x =>
x.CompanyCode.Equals("M5QoKF4AS0"))));
Here mocContext is my Moq'd Database, Company is the table that I want to perform the FindAsync on, the Get CompanyList just pulls from the data the populated the table. Hopefully this helps

I circumvented this mocking by using .Where(entity => entity.PrimaryKey == key).FirstOrDefaultAsync() in place of .FindAsync(key) as FirstOrDefaultAsync did not require a separate mocking and logic is also same between both approaches

For anyone struggling with this, here's another way of doing it:
First: Create a mock of the DbContext and the DbSet, ex:
private static readonly Mock<ApplicationDbContext> mockDbContext = new();
private static readonly Mock<DbSet<Game>> mockGameSet = new();
Second: Setup the Get of the DbSet in the Mocked DbContext, like this:
mockDbContext.SetupGet(_ => _.Games).Returns(mockGameSet.Object);
Third, and Last: Setup the FindAsync() in the mocked DbSet like this:
mockGameSet.Setup(x => x.FindAsync(It.IsAny<int>())).ReturnsAsync(game);

Related

Why the method doesn't work, however the same algorithm in another method works?

I have a DB with Entity Framework, using a repository design pattern. There's a method in my repository which gets two inputs, an entity and an IQuerable<Entity> collection. The method algorithm should return another entity from the collection, based on the entity input (for the sake of simplicity imagine a dating app where the userA gets userB as a recommendation, based on userA's preferences).
I have a test class library for testing the repository, using nUnit and MOQ. I setup the mock correctly to return a fake user list. and then I tested the method.
Here is the twist. The unit test fails, because the repository method returns null. However if I copy and paste the algorithm right into the unit test it returns the correct data. What's wrong? How is that possible? In the below code I commented the right and wrong stuff...
Repository method:
public IUser SearchForDate(IUser entity, IQueryable<USERS> users)
{
var userPartner = users.Where(x => x.Interested == entity.Male)
.Where(x => x.MinAge < entity.Age)
.Where(x => x.MaxAge > entity.Age)
.Where(x => x.WantToDate == true).FirstOrDefault();
return userPartner;
}
At setup:
this.userRepo.Setup(x => x.GetAllIUsers()).Returns(testUsers);
this.userRepo.Setup(x => x.GetAll()).Returns(testUsers2.AsQueryable());
IUserRepository Repo = this.userRepo.Object;
At unit test:
[TestCase("Andrew", "Angela")]
public void SearchForPartner_ReturnsTheCorrectPartner(string userName, string partnerName)
{
//Assert - Act
var users = Repo.GetAll();
var userNeedsPartner = users.Single(x => x.Nickname == userName); //this return the correct user - Andrew
var partner = Repo.SearchForDate(userNeedsPartner, Repo.GetAll()); //NOT GOOD, WHY????Even if I use users instead of Repo.GetAll() - this mothafucka returns null.
var partnerForUser = Repo.GetAll().Where(x => x.Interested == userNeedsPartner.Male)
.Where(x => x.MinAge < userNeedsPartner.Age)
.Where(x => x.MaxAge > userNeedsPartner.Age)
.Where(x => x.WantToDate == true).FirstOrDefault(); //GOOD, WHY??? - This returns the correct user - Angela
//Arrange
Assert.That(partner.Nickname, Is.EqualTo(partnerName)); //NULLReferenceException...
}
Alright I finally figured out a solution to this. As I declared my Mock as private Mock<IUserRepository> userRepo = new Mock<IUserRepository>(); and then declared a repository as IUserRepository Repo = userRepo.Object; so when I called the Repo.SearchForDate(IUser entity, IQuerable<USERS> users); method, it was returning null all the time, because Repo was just an interface without real implementation. So I decided to change the Mock's type from IUserRepository to UserRepository and boom... Suddenly it all started to working. Anyway, thanks guys for helping me out! :)

Mock extension methods IElasticClient

Is there a way to mock the following
var result = await Client.SearchAsync<IndexedSite>(d => d
.Index(SiteIndexName)
.Query(q => q.MatchAll())
.Sort(sd => sd.Field(s => s.Name, SortOrder.Ascending))
.Take(c_maxSiteListSize));
Would one use .Callbacks in this situation?
My current setup:
private Mock<IElasticClient> _client = new Mock<IElasticClient>();
private Mock<ISearchResponse<IndexedSite>> indexedSite = new Mock<ISearchResponse<IndexedSite>>();
_client.Setup(x =>
x.SearchAsync<IndexedSite>(It.IsAny<Func<SearchDescriptor<IndexedSite>, ISearchRequest>>(),
default(CancellationToken))).Returns(Task.FromResult(indexedSite.Object));
This works, and it does return indexedSite, however it does not 'Cover' .Index/.Query/.Sort/.Take extension methods, which is what I want.
Per #Olegl answer. It is not possible to Mock extension methods. You need to refactor and get rid of extension methods in order to make it testable
More info here

How do I test extension method of Nhibernate which does not return the value even after specifying return in fakeiteasy?

I have a class like below where using Fluent Nhibernate I am getting data from database
public class MyActualClass
{
public MyActualClass(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
public List<AnnualInformation> GetData()
{
using (session = sessionFactory.OpenSession())
{
var result = session.QueryOver<AnnualInformation>()
.SelectList(list => list
.Select(x => x.Id)
.Select(x => x.CreationDate)
.Select(x => x.AnnualAmount)
.Select(x => x.AnnualCurrency)
.Select(() => monthlyAlias.MonthlyAmount)
.Select(() => monthlyAlias.MonthlyCurrency)
.Select(() => shareAlias.CurrentSharevalue)
.Select(() => miscAlias.MarketValueAmount)
).Where(a => a.Id == 123456).List<AnnualInformation>();
}
}
}
I Have written unit test case for above method like below
public class MyTestClass
{
private static ISessionFactory sessionFactory;
private static ISession session;
public MyTestClass()
{
sessionFactory = A.Fake<ISessionFactory>();
session = A.Fake<ISession>();
A.CallTo(() => sessionFactory.OpenSession()).Returns(session);
}
[Fact]
public void MyTest()
{
var annualDetails =
new AnnualInformation
{
Id= 1,
AnnualCurrency= "string",
AnnualAmount= "Example"
}
var listOfAnnualInformation=
new List<AnnualInformation>
{
annualDetails
};
A.CallTo(session.QueryOver<AnnualInformation>()).WithReturnType<IList<AnnualInformation>>().Returns(listOfAnnualInformation);
var myInstance = new MyActualClass(sessionFactory);
myInstance.GetData();
}
}
Actually if you see below code
session.QueryOver()
.SelectList(...
will return "result" in method GetData(). After that I am manipulating "result" datastructure to get Id, CreationDate, AnnualAmount, AnnualCurrency
Therefore it is very important that some value is returned from "result". My problem is the count of resulty is always 0.
I want the below line of code
A.CallTo(session.QueryOver()).WithReturnType>().Returns(listOfAnnualInformation);
to return a list with atleast one element. Now i believe i clarified my requirements
Please suggest what should be done here ?
Based on the new code (which still doesn't quite compile - missing ;, result isn't returned from GetData, and if it were, the return type of GetData should be IList<AnnualInformation>, but with those changes I was able to get a test to run) I can offer some commentary:
A.CallTo(session.QueryOver<AnnualInformation>()).WithReturnType<IList<AnnualInformation>>()
.Returns(listOfAnnualInformation);
Configures the object that comes back from calling session.QueryOver<AnnualInformation>(). (Note there's no lambda here, so this line actually calls QueryOver.)
session is a Fake, and so when you call QueryOver<AnnualInformation>() on this line, it will return a new Fake IQueryOver. The "WithReturnType…Returns…" configures the new Fake IQueryOver to return listOfAnnualInformation when any method that returns a IList<AnnualInformation> is called.
However, when Fakes' methods are called, unless they've been configured to do something different, they return a new object. So inside GetData when you call QueryOver, you get a different fake IQueryOver, which has not been configured at all. That's one problem.
Second problem: the call to SelectList will return yet another faked IQueryOver.
We can work around all these things:
var aFakeQueryOver = A.Fake<IQueryOver<AnnualInformation, AnnualInformation>>();
A.CallTo(aFakeQueryOver).WithReturnType<IQueryOver<AnnualInformation, AnnualInformation>>()
.Returns(aFakeQueryOver);
A.CallTo(aFakeQueryOver).WithReturnType<IList<AnnualInformation>>()
.Returns(listOfAnnualInformation);
A.CallTo((() => session.QueryOver<AnnualInformation>())).Returns(aFakeQueryOver);
And now the faking behaves as we want. However, all we've done is short-circuit all the logic in GetData, except to see that it uses the sessionFactory to open a session, and then QueryOver on that session. SelectList and Where and List have all been bypassed.
My usual advice in this situation is to make your data access layer as thin as possible and to integration test it. Alternatively, I've seen people suggest having NHibernate use an in-memory MySql database. Still an integration test of sorts, but at least it's more isolated.

How do I mock multiple levels of DbSet.Include lambdas?

I'm using Moq to write unit tests that use Entity Framework 6 DbSet and DbContext objects. I have a service method with a cascading/multi-level Include and I can't figure out how to set it up for testing. The service method looks something like this:
return DataContext.Cars
.Include(p => p.Model)
.Include(p => p.Model.Make)
.Select(c => new
{
Key = c.CarId,
Value = string.Format("{0} {1} {2}", c.Model.Make.Name, c.Model.Name, c.Trim)
}
).ToArray();
I know that I have to setup the Include to return the mocked object, like this:
mockCarDbSet.Setup(m => m.Include(It.IsAny<string>())).Returns(mockCarSet.Object);
But I'm getting a null reference exception from the cascaded .Include(p => p.Model.Make). How do I set up Moq to handle multiple levels of Include?
EDIT
OK, so it turns out that I can't use It.IsAny<string> for Include calls that use lambdas instead of strings, so now I have two problems:
How do I setup a mock with Include that accepts a lambda?
Will the setup for above cascade to multiple levels?
include() is a static method(extension method).
Moq doesn't support a static methods mock(read this link).
To test your code you need to set your mockCarDbSet to return IQueryable<Car>:
var carQuery = new List<Car>
{
//add cars
}
IQueryable<Post> query = carQuery.AsQueryable();
return query as a result of DataContext.Cars
Those steps will work around the static method problem.
So thanks to #Old Fox reminding me that Moq won't work with static members, I found a way to do this using Microsoft Fakes. Shims allows you to shim static methods. I used Moq to set up Mock<DbSet> objects for each of the entities:
var carData = new List<Car>{new Car{ Trim = "Whatever" }};
var mockCarSet = new Mock<DbSet<Car>>();
mockCarSet.As<IQueryable<Car>>().Setup(m => m.Provider).Returns(carData.Provider);
mockCarSet.As<IQueryable<Car>>().Setup(m => m.Expression).Returns(carData.Expression);
mockCarSet.As<IQueryable<Car>>().Setup(m => m.ElementType).Returns(carData.ElementType);
mockCarSet.As<IQueryable<Car>>().Setup(m => m.GetEnumerator()).Returns(carData.GetEnumerator);
var mockMakeSet = new Mock<DbSet<Make>>();
//do the same stuff as with Car for IQueryable Setup
var mockModelSet = new Mock<DbSet<Model>>();
//do the same stuff as with Car for IQueryable Setup
using(ShimsContext.Create())
{
//hack to return the first, since this is all mock data anyway
ShimModel.AllInstances.MakeGet = model => mockMakeSet.Object.First();
ShimCar.AllInstances.ModelGet = car => mockModelSet.Object.First();
//run the test
}

Is .Callback the right way to mock a void-returning method using Moq?

I would like to unit test an Add method in a repository that returns void. I'm interested in testing the actual adding of elements without hitting the database (not whether Add was called or not). Is this the correct way?
var list = new List<Foo>();
var repo = new Mock<IFooRepository>();
repo.Setup(x => x.Add(It.IsAny<Foo>()))
.Callback((Foo f) =>
{
list.Add(f);
});
repo.Object.Add(new Foo { FooId = 1 });
Assert.IsTrue(list.Any(x => x.FooId == 1));
No, the only thing you're testing here is Moq itself. You could try mocking the underlying layer, e.g. ISession if you're using Nhibernate.

Categories