Dzmitry Shauchuk
Dzmitry Shauchuk

Reputation: 454

Mocking FindAsync method

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?

Upvotes: 5

Views: 5686

Answers (4)

bardhyl sllamniku
bardhyl sllamniku

Reputation: 31

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);

Upvotes: 2

Abdul Hameed
Abdul Hameed

Reputation: 992

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

Upvotes: 0

DWCoder
DWCoder

Reputation: 25

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

Upvotes: 1

Fredrik
Fredrik

Reputation: 2317

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(), ...

Upvotes: 4

Related Questions