Setup a mocked EF Service method - c#

I have the following method in my NewsDataService class
public IEnumerable<NewsModel> GetImportantNews()
{
var result = this.newsfeedRepository.GetAll(
x => x.IsImportant == true,
x => new NewsModel()
{
Creator = x.User.UserName,
AvatarPictureUrl = x.User.AvatarPictureUrl,
Content = x.Content,
CreatedOn = x.CreatedOn
})
.OrderByDescending(x => x.CreatedOn);
return result;
}
My question is...
How do I setup the mocked service method (GetImportantNews),
so that it returns a list of NewsModel which are "Important"?
My idea is something like this, but it is not working so far, because it is always returning the full list.
var expectedResult = new List<Newsfeed>()
{
new Newsfeed()
{
IsImportant = false,
},
new Newsfeed()
{
IsImportant = true
}
};
mockedNewsfeedRepository
.Setup(x => x.GetAll(
It.IsAny<Expression<Func<Newsfeed, bool>>>(),
It.IsAny<Expression<Func<Newsfeed, NewsModel>>>()
)).Returns(expectedResult);
Basically what I want is my "expectedResult" to be filtered by the logic in the method.

You have access to the invocation arguments when returning a value. Apply the predicate and projection expression arguments to the fake data source using linq like in the example below.
mockedNewsfeedRepository
.Setup(x => x.GetAll(
It.IsAny<Expression<Func<Newsfeed, bool>>>(),
It.IsAny<Expression<Func<Newsfeed, NewsModel>>>()
))
// access invocation arguments when returning a value
.Returns((Expression<Func<Newsfeed, bool>> predicate, Expression<Func<Newsfeed, NewsModel>> projection) =>
expectedResult.Where(predicate.Compile()).Select(projection.Compile())
);
Source: Moq Quickstart

Related

Mock a function that returns a Expression Tree in a class

Scenario:
I have a class with methods, in which one method returns a expression tree.
How can I mock that method.
Code:
public Expression<Func<SpecFinderDataModel, bool>> BuildDynamicWhereClause(DataTableAjaxPostModel model)
{
var predicate = PredicateBuilder.New<SpecFinderDataModel>(true);
if (_stringValidator.IsValid(model.search.value))
predicate = _basicSearchService.DoSearch(model.search.value, predicate);
var searchData = model.columns.Where(x => x.search.value != null);
predicate = _advancedSearchService.DoSearch(model.isActive, searchData, predicate);
return predicate;
}
Here _advancedSearchService.DoSearch() this method returns a Expression<Func<SpecFinderDataModel, bool>>. I wrote a test which is given below
Test:
[TestMethod]
[TestCategory("BuildDynamicWhereClause")]
public void BuildDynamicWhereClauseTest()
{
DataTableAjaxPostModel searchmodel = new DataTableAjaxPostModel()
{
columns = new List<Column>()
{
new Column() {
data ="Status",
orderable ="true",
searchable ="true",
search = new Search() {
regex = "false",
value ="TestStatus"
}
}
},
search = new Search()
};
IFinderBuildQueryFlow _finderBuildQueryFlow = new FinderBuildQueryFlow(
_mockBasicSearchService.Object, _mockAdvancedSearchService.Object, _mockStringValidator.Object);
var predicate = PredicateBuilder.New<SpecFinderDataModel>(true);
_mockStringValidator.Setup(x => x.IsValid(searchmodel.search.value)).Returns(false);
var searchData = searchmodel.columns.Where(x => x.search.value != null);
_mockAdvancedSearchService.Setup(x => x.DoSearch(searchmodel.isActive, searchData, predicate).Compile()(model)).Returns(true);
var test = _finderBuildQueryFlow.BuildDynamicWhereClause(searchmodel).Compile()(model);
}
Everything before
_mockAdvancedSearchService.Setup(x => x.DoSearch(searchmodel.isActive, searchData, predicate).Compile()(model)).Returns(true); works fine.
But I don't know how to mock advancedSearch.DoSearch() method.
Any advice would be really helpful. Thanks
Update #1:
This is the error when that line of code is executed
Update #2:
so here the predicate is returned as null.
and in the test
I'm getting the error like this
If you want to mock the call to _advancedSearchService.DoSearch() you will have to set it up as follows:
Expression<Func<SpecFinderDataModel, bool>> query = model => true;
_mockAdvancedSearchService.Setup(x => x.DoSearch(searchmodel.isActive, It.IsAny<IEnumerable<Column>>(), It.IsAny<Expression<Func<SpecFinderDataModel, bool>>>())).Returns(query);
Given that the searchdata parameter is created in the method itself you will need to accept any value for it.
Given that the predicate parameter is created in the method itself you will need to accept any value for it.

How to test Add method with Moq in C#

I try write a unit test for Add method from repository class. I'm using EF6 and Moq. My test method looking that:
public static Mock<DbSet<T>> CreateDbSetMock<T>(IEnumerable<T> elements) where T : class
{
var elementsAsQueryable = elements.AsQueryable();
var dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(m => m.Provider).Returns(elementsAsQueryable.Provider);
dbSetMock.As<IQueryable<T>>().Setup(m => m.Expression).Returns(elementsAsQueryable.Expression);
dbSetMock.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(elementsAsQueryable.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(elementsAsQueryable.GetEnumerator());
return dbSetMock;
}
[Test()]
public void AddTest()
{
// Arrange
Mock<DbSet<Tytul>> titlesMock = CreateDbSetMock(new List<Tytul>());
Mock<OzinDbContext> titlesContextMock = new Mock<OzinDbContext>();
titlesContextMock.Setup(x => x.Tytuly).Returns(titlesMock.Object);
titlesMock.Setup(x => x.Add(It.IsAny<Tytul>())).Returns((Tytul t) => t);
IRepository<Tytul> tytulRepository = TytulRepository(titlesContextMock.Object);
Tytul tytul = new Tytul
{
Identyfikator = "ABC"
};
// Act
tytulRepository.Add(tytul);
// in Add method:
//dbContext.Tytuly.Add(entity);
//dbContext.SaveChanges();
Tytul tytulInDb = tytulRepository.GetDetail(t => t.Identyfikator == "ABC");
// in GetDetail method:
//return dbContext.Tytuly.FirstOrDefault(predicate);
// Assert
Assert.AreEqual(tytulInDb.Identyfikator, tytul.Identyfikator);
}
My problem is GetDetail method returns null, but I expected the tytulInDb object. What is wrong? How write thist test correct?
Extract the fake data source for the DbSet into a local variable so it can be interacted with later in the test setup. Add a Callback to the Add setup to add the passed argument to the data source so that there is actual data to be acted upon by the mock when invoked.
// Arrange
var data = new List<Tytul>(); //<<< local variable
Mock<DbSet<Tytul>> titlesMock = CreateDbSetMock(data);
var titlesContextMock = new Mock<OzinDbContext>();
titlesContextMock.Setup(x => x.Tytuly).Returns(titlesMock.Object);
titlesMock
.Setup(x => x.Add(It.IsAny<Tytul>()))
.Returns((Tytul t) => t)
.Callback((Tytul t) => data.Add(t)); //<<< for when mocked Add is called.
IRepository<Tytul> tytulRepository = TytulRepository(titlesContextMock.Object);
//...Code removed for brevity
Also when setting up the DbSet Mock use a delegate for the Returns to allow for multiple enumerations as returning just the value will only allow for one pass of the forward only enumerator.
dbSetMock.As<IQueryable<T>>()
.Setup(m => m.GetEnumerator())
.Returns(() => elementsAsQueryable.GetEnumerator()); //<<< note delegate

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