Moq Verify that Method was called with any expression - c#

I'm new to Moq and I'm trying to Mock my repository.
The method I'm Writing a unit test for is calling the repository like this:
var paymentState = _agreementPaymentStateRepository.SingleOrDefault(
s => s.Agreement.ID == agreementID);
I'm trying to set up my moq like this:
_agreementPaymentStateRepositoryMock
.Setup(m => m.SingleOrDefault(s => s.AgreementID == 1))
.Returns(AgreementPayMentStateMocks.GetOne);
I pass my mocked repository to the class but the paymentState variable is null after the call is made. (I would gladely skip specifying the expression as well).
Any help is much appreciated.
public PaymentState GetPaymentState(int agreementID)
{
try
{
_log.AgreementPaymentStateServiceGetStateStart(agreementID);
var paymentState =
_agreementPaymentStateRepository.SingleOrDefault(s => s.Agreement.ID == agreementID);
var stateToGet = MapStateToGet(paymentState);
_log.AgreementPaymentStateServiceGetStateReturn(agreementID, paymentState.LatestStatus);
return stateToGet;
}
catch (Exception ex)
{
_log.ServiceException(ex.ToString());
throw;
}
}
and the test:
var paymentState = AgreementPayMentStateMocks.GetPayMentState();
_agreementPaymentStateRepositoryMock.Setup(m => m.SingleOrDefault(s => s.AgreementID == 1)).Returns(AgreementPayMentStateMocks.GetOne);
var service = new AgreementPaymentStateService(_agreementPaymentStateRepositoryMock.Object, _log.Object);
var result = service.GetPaymentState(1);
_agreementPaymentStateRepositoryMock.Verify(m => m.Match(aps => aps.SingleOrDefault(s => s.AgreementID == 1)), Times.Exactly(1));

Instead of having a concrete predicate in the SingleOrDefault call, use Moq's It.IsAny<T> method:
_agreementPaymentStateRepositoryMock
.Setup(m => m.SingleOrDefault(It.IsAny<Expression<Func<bool,PaymentState>>>()))
.Returns(AgreementPayMentStateMocks.GetOne);

Related

Mocking a method return inside tested method

so I am trying to write an unit test for this method (I'm using xUnit and MOQ):
public override FilteredFeedPagesResult<ProgramPage> Create(FilteredFeedContext context)
{
var pages = _pageFilteringService.GetFilteredFeedPages(
context.Reference,
context.Culture,
context.Filters,
_customPageFilter);
if (context.IsSortedByDate && context.PageType.Name is nameof(ProgramPage))
{
var sortedPages = pages.OfType<ProgramPage>()
.Select(page => new
{
Page = page,
ScheduledStartDate = page.GetProgramPairings(page).Select(pairing => pairing.ScheduledStartDate).DefaultIfEmpty(DateTime.MaxValue).Min(),
})
.OrderBy(item => item.ScheduledStartDate)
.ThenBy(item => item.Page.Name)
.Select(item => item.Page);
return Map(sortedPages, context.PageNumber, context.PageSize);
}
return Map(pages.OrderByDescending(x => x.Date), context.PageNumber, context.PageSize);
}
As you can see, inside the LINQ statement in if clause there is a GetProgramPairings being invoked. It is supposed to get events for particular page from the database: Then, based on it, the order of events is created.
Code of the GetProgramPairings method:
public IEnumerable<ProgramPairing> GetProgramPairings(ProgramPage page)
{
var pairings = new List<ProgramPairing>();
if (page != null && page.ProgramPairings != null && page.ProgramPairings.FilteredItems.Any())
{
foreach (ContentAreaItem item in page.ProgramPairings.FilteredItems)
{
if (contentLoader.Service.TryGet<ProgramPairing>(item.ContentLink, out ProgramPairing pairing))
{
pairings.Add(pairing);
}
}
}
return pairings;
}
This is what my test looks like so far:
[Fact]
public void Create_IsSortedByDateTrueAndPageTypeProgramPage_ReturnsSortedPages()
{
var homePageMock = SetupHomePage();
var returnedPages = new[] { CreateProgramPage(DateTime.UtcNow.AddDays(-5)), CreateProgramPage(DateTime.UtcNow) };
var context = new FilteredFeedContext(homePageMock.Object, 0, 6, typeof(ProgramPage), null, null, true);
_filteredFeedPagesFilteringServiceMock.Setup(x => x.GetFilteredFeedPages<ProgramPage>(It.Is<ContentReference>(p => p.ID == homePageMock.Object.ContentLink.ID), It.Is<CultureInfo>(c => c.LCID == homePageMock.Object.Language.LCID), It.IsAny<IDictionary<string, string>>(), It.IsAny<IPageCustomFilter<ProgramPage>>()))
.Returns(returnedPages);
var result = _sut.Create(context);
//will need to create an assert to check if items in the list are in right order
}
My question is, how to mock the IEnumerable parings returned fromGetProgramPairings inside of the main method being tested ?
The problem here is the Single Responsibility Principle. Think thoroughly, is the ProgramPage's responsibility to get program pairings? This logic should be encapsulated in some other service. Once you do that, you can easily mock that service. Good luck!

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) {
//...
}
});

Moq cannot instantiate service that includes lambda expression

I want to mock the following method with Moq:
T GetOne(Expression<Func<T, bool>> expression);
which is called in the following method:
public GetTCNotifyFCResponse GetTCNotifyFC(string operationNumber)
{
var response = new GetTCNotifyFCResponse { IsValid = false };
try
{
var tcAbstract = _tcAbstractRepository
.GetOne(x => x.Operation.OperationNumber == operationNumber);
if (tcAbstract == null)
{
response.ErrorMessage = Localization.GetText(WORKFLOW_DONT_STARED);
return response;
}
[...]
The test code is:
var mockAbstractRep = new Mock<ITCAbstractRepository>();
mockAbstractRep
.Setup(s => s.GetOne(x => x.Operation.OperationNumber == operationNumber))
.Returns(entity);
but when running it I get a null "tcAbstract" result... "operationNumber" and "entity" variables are filled before and have not been included here for simplicity.
What am I doing wrong?
Try this and see if it helps
var mockAbstractRep = new Mock<ITCAbstractRepository>();
mockAbstractRep
.Setup(s => s.GetOne(It.IsAny<Expression<Func<EntityType, bool>>>()))
.Returns(entity);
replace EntityType with the type that your method requires

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

Mocking LINQ Expressions - Moq

How do I mock something that is - Expression> using Moq?
I'm trying to mock a call to my repo layer that takes in a LINQ Expression for constructing a query. I'm trying the below syntax but it fails. The SearchFor method doesn't get called.
var array = new Employee[1];
array[0] = new Employee() { ID = 1234, Name = "Test" };
MockEmployeeRepo.Setup(x => x.SearchFor(It.IsAny<Expression<Func<Employee, bool>>>()))
.Returns(array.AsQueryable);
var list = EmployeeService.GetEmployees("Test");
MockEmployeeRepo.Verify(x => x.SearchFor(x1 => x1.Name == "Test"), Times.Once());
Assert.AreEqual("Test", list[0].Name);
Here the GetEmployees method looks like below.
public IEnumerable<Employee> GetEmployees(string name)
{
return repo.SearchFor(x => x.Name == name);
}
Moq does not supports with Expression function so here is the best solution. Use this nuget package Moq.Expression
// import namespace
using MoqExpression;
// it will work
MockEmployeeRepo.Setup(x => x.SearchFor(MoqHelper.IsExpression<Employee>(s => s.Name.Equals("Test")))).Returns(array.AsQueryable);
For more documentation: https://github.com/ovaishanif94/Moq.Expression

Categories