Moq Expression with Constraint ... It.Is<Expression<Func<T, bool>>> - c#

Ok, I am having a hard time trying to figure out how to setup a moq for a method that takes in an expression. There are a lot of examples out there of how to to It.IsAny<>... that is not what I am after. I am after doing with a constraint, so It.Is<>. I have set it up but it never returns the value I have asked it to return.
// Expression being setup
Expression<Func<UserBinding, bool>> testExpression = binding =>
binding.User.Username == "Testing Framework";
// Setup of what expression to look for.
this.bindingManager.Setup(
c => c.GetUserBinding(It.Is<Expression<Func<UserBinding, bool>>>
(criteria => criteria == testExpression)))
.Returns(new List<UserBinding>() { testBinding }.AsQueryable());
// Line of code call from within the class being tested. So this is being mocked and should return the defined object when the same lambda is passed in.
this.bindingManager.GetUserBinding(b => b.User.Username == username)
.SingleOrDefault();
// class under test. So for the test this is being called.
// so this is the method being called and inside this method is where the binding manager is being mocked and called.
var response = this.controller.SendMessage(message, true).Result;
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
// inside the controller.SendMessage method this method is called with the lambda expression. I have verified the usernames match but when the setup is It.Is this returns null instead of the object setup in the "setup" call.
this.bindingManager.GetUserBinding(b => b.User.Username == username)
.SingleOrDefault();
If I change the setup to It.IsAny... It works and returns the expected object setup in the "returns" method.
I have found a few examples of how to do this on the web one is doing it this way the other is using compile but I can't get that to work either. How do you get this to work for a specific expression?
Update with working solution based on answer
#carlos-alejo got me going in the right direction or at least kicked me back to the Compile action. I was thinking about it wrong. I have the solution working now based on using compile. The key thing to understand about compile is you are giving it an object by which to evaluate/generate the expression for.
So in my case if some one is giving me an expression like this:
binding => binding.User.Username == "Testing Framework";
I need to have a UserBinding like this:
var testBinding = new UserBinding { Binding = new Binding { Name = "Default binding" }, Domain = "test.com", User = new User() { Username = "Testing Framework" } };
I can then create my "setup" call like this:
this.bindingManager.Setup(c => c.GetUserBinding(It.Is<Expression<Func<UserBinding, bool>>>(y => y.Compile()(testBinding))))
.Returns(new List<UserBinding>() { testBinding }.AsQueryable());
This works and in my case returns me back the test binding object as I have setup. If you change the testBinding to be (notice I changed the user name):
var testBinding = new UserBinding { Binding = new Binding { Name = "Default binding" }, Domain = "test.com", User = new User() { Username = "Testing Framework2" } };
It will not work because the code inside my system under test generates an expression looking for "Test Framework"
Maybe it was just me not connecting the dots on this but hopefully it helps others.

It seems that the real problem here is how to compare two lambda expressions, as you try to do in the It.Is<Expression<Func<UserBinding, bool>>> (criteria => criteria == testExpression) clause. Using #neleus's answer to this question, I could come up with this test that actually passes:
readonly Mock<IBindingManager> bindingManager = new Mock<IBindingManager>();
[Test]
public void TestMethod()
{
Expression<Func<string, bool>> testExpression = binding => (binding == "Testing Framework");
bindingManager.Setup(c => c.GetUserBinding(It.Is<Expression<Func<string, bool>>>(
criteria => LambdaCompare.Eq(criteria, testExpression)))).Returns(new List<string>());
var oc = new OtherClass(bindingManager.Object);
var actual = oc.Test(b => b == "Testing Framework");
Assert.That(actual, Is.Not.Null);
bindingManager.Verify(c => c.GetUserBinding(It.Is<Expression<Func<string, bool>>>(
criteria => LambdaCompare.Eq(criteria, testExpression))), Times.Once());
}
Please note the use of the LambdaCompare.Eq static method to compare that the expressions are the same. If I compare the expressions just with == or even Equals, the test fails.

When I was looking for the way to to mock Where() and filter some data,
in code under tests looks like:
Repository<Customer>().Where(x=>x.IsActive).ToList()
I could design such example based on answers form others:
var inputTestDataAsNonFilteredCustomers = new List<Customer> {cust1, cust2};
var customersRepoMock = new Mock<IBaseRepository<Customer>>();
IQueryable<Customer> filteredResult = null;
customersRepoMock.Setup(x => x.Where(It.IsAny<Expression<Func<Customer, bool>>>()))
.Callback((Expression<Func<Customer, bool>>[] expressions) =>
{
if (expressions == null || expressions.Any() == false)
{
return;
}
Func<Customer, bool> wereLambdaExpression = expressions.First().Compile(); // x=>x.isActive is here
filteredResult = inputTestDataAsNonFilteredCustomers.Where(wereLambdaExpression).ToList().AsQueryable();// x=>x.isActive was applied
})
.Returns(() => filteredResult.AsQueryable());
Maybe it will be helpful for feather developers.

Related

xUnit mock method with lambda expression as input parameter

I have a method like this one:
public Task<IEnumerable<VwSubscriptionProductsPf>> GetVwSubscriptionProductsBy(
Expression<Func<VwSubscriptionProductsPf, object>> lambda)
{
var result = GetList(lambda);
return result;
}
The method is called like this:
var products = await _uow.VwSubscriptionProductsRepository
.GetVwSubscriptionProductsBy(s => s.SubscriptionId == subscription.Id);
And now I want to mock the return of the method using xUnit.
var products = new List<VwSubscriptionProductsPf>
{ new VwSubscriptionProductsPf { SubscriptionId = 1, Name = "Product 1" }};
_uow.Setup(x => x.VwSubscriptionProductsRepository
.GetVwSubscriptionProductsBy(s => s.SubscriptionId == 1))
.Returns(Task.FromResult(products.AsEnumerable()));
Can you tell me what am I missing?
PS. The problem is that the GetVwSubscriptionProductsBy returns an empty IEnumerable, and I'm waiting for the IEnumerable with one element manually created by me.
I found the answer, the method can be mocked like this:
_uow.Setup(x => x.VwSubscriptionProductsRepository.GetVwSubscriptionProductsBy(It.IsAny<Expression<Func<VwSubscriptionProductsPf, object>>>()))
.Returns(Task.FromResult(products.AsEnumerable()));

Entity-Framework using expressions to build global and reusable filter/query-rules

Given the following linq-query:
var query1 = dbContext.MainTable.Where(m => m.MainId == _mainId).SelectMany(sub => sub.SubTable1)
.Select(sub1 => new
{
sub1.CategoryName,
VisibleDivisions = sub1.SubTable2
.Where(sub2 => sub2.Status == "Visible")
.Select(sub2 => new
{
/* select only what needed */
})
});
Starting from my main-table, I want to get all sub1's selected together with all the sub2's related to the sub1.
The query works as expected, generating a single query which will hit the database.
My question is regarding the inner Where-part, as of this filter will be used at several other parts in the application. So I would like to have this "visible-rule" defined at a single place (DRY-principle).
As of the Where is expecting an Func<SubTable2, bool> I have written the following property
public static Expression<Func<SubTable2, bool>> VisibleOnlyExpression => sub2 => sub2.Status == "Visible";
and changed my query to
var query1 = dbContext.MainTable.Where(m => m.MainId == _mainId).SelectMany(sub => sub.SubTable1)
.Select(sub1 => new
{
sub1.CategoryName,
VisibleDivisions = sub1.SubTable2
.Where(VisibleOnlyExpression.Compile())
.Select(sub2 => new
{
/* select only what needed */
})
});
This throws me an exception, stating Internal .NET Framework Data Provider error 1025..
I already tried changing to .Where(VisibleOnlyExpression.Compile()) with the same error.
I know that this is because EntityFramework is trying to transalte this into SQL which it can not.
My question is: How can I have my "filter-rules" defined at a single place (DRY) in code but have the still usable in Where-, Select-, ... -clauses which can be used on IQueryable as well as on ICollection for inner (sub-)queries?
I would love to be able to write something like:
var query = dbContext.MainTable
.Where(IsAwesome)
.SelectMany(s => s.SubTable1.Where(IsAlsoAwesome))
.Select(sub => new
{
Sub1sub2s = sub.SubTable2.Where(IsVisible),
Sub2Mains = sub.MainTable.Where(IsAwesome)
});
whereas the IsAwesome-rule is called first on IQueryable<MainTable> to get only awesome main-entries and later on ICollection<MainTable> in the sub-select to fetch only awesome main-entries related to a specific SubTable2-entry. But the rule - defining a MainTable-entry as awesome - will be the same, no matter where I call/filter for it.
I guess the solution will need the use of expression-trees and how they can be manipulated, so they will be translatable to plain SQL but I don't get the right idea or point to start with.
You can get something close to what are you asking for using the LinqKit AsExpandable and Invoke extension methods like this:
var isAvesome = IsAwesome;
var isAlsoAwesome = IsAlsoAwesome;
var isVisible = IsVisible;
var query = dbContext.MainTable
.AsExpandable()
.Where(mt => isAwesome.Invoke(mt))
.SelectMany(s => s.SubTable1.Where(st1 => isAlsoAwesome.Invoke(st1)))
.Select(sub => new
{
Sub1sub2s = sub.SubTable2.Where(st2 => isVisible.Invoke(st2)),
Sub2Mains = sub.MainTable.Where(mt => isAwesome.Invoke(mt))
});
I'm saying close because first you need to pull all the expressions needed into variables, otherwise you'll get the famous EF "Method not supported" exception. And second, the invocation is not so concise as in your wish. But at least it allows you to reuse the logic.
AFAIK what you are trying to do should be perfectly possible:
// You forgot to access ".Status" in your code.
// Also you don't have to use "=>" to initialize "IsVisible". Use the regular "=".
public static Expression<Func<SubTable2, bool>> IsVisible = sub2 =>
sub2.Status == "Visible";
...
VisibleDivisions = sub1
.SubTable2
// Don't call "Compile()" on your predicate expression. EF will do that.
.Where(IsVisibleOnly)
.Select(sub2 => new
{
/* select only what needed */
})
I would prepare extension method like below:
public static IQueryable<SubTable2> VisibleOnly(this IQueryable<SubTable2> source)
{
return source.Where(s => s.Status == "Visible");
}
An then you can use it in that way:
var query = dbContext.Table.VisibleOnly().Select(...)

MV3 Test Project with Moq, how to return an object when certain expression is used?

Here is my code:
[TestMethod]
public void LoginUnregisteredUserShouldFail()
{
Mock<IRepository<User>> _repo = new Mock<IRepository<User>>();
UserServiceForTest target = new UserServiceForTest(_repo.Object, new HashingService());
var unregisteredTestUser = new User() { Email = "a", Nombre = "test", Password = "test" };
var registeredHashedTestUser = new User() { Email = "test#test.com", Nombre = "test", Password = "qUqP5cyxm6YcTAhz05Hph5gvu9M=" };
Expression<Func<User, bool>> expression = a => a.Email == "a";
_repo.Setup(a => a.Single(It.Is<Expression<Func<User,bool>>>(l => l.ToString() == expression.ToString()))).Returns(unregisteredTestUser);
Assert.IsFalse(target.ValidateCredentials(unregisteredTestUser));
}
I want to query the Single method of my repo, matching Email, and I want the result to be the specified User.
I dont know what I'm doing wrong but I always receive null.
EDIT:
My implementation is the following:
private string GetUserPasswordFromDbByUserName(string userName)
{
Expression<Func<User, bool>> ax = a => a.Email == userName;
var axx = ax.ToString();
var user = _repo.Single(ax);
if (user != null)
return user.Password;
else
return string.Empty;
}
It receives a string userName and for some reason, the .ToString() returns 'a => (a.Email == value(Casita.Services.UserService+<>c__DisplayClass5).userName)' instead of 'a => (a.Email == "a")'. Makes no sense to me, but I'm guessing this is the reason the comparison is failing.
Your problem is likely the equality comparison in the Is expression parameter. They are probably not the same when converted to strings so your equality comparison might be failing. The following question details how to compare [Func] delegates:
How to check if two Expression<Func<T, bool>> are the same
Nievely I'll suggest the following might work. Note this would use http://evain.net/blog/articles/2008/02/06/an-elegant-linq-to-db4o-provider-and-a-few-linq-tricks which might require adding a reference/download of db4o. I stopped research at that point.
Func<Expression, Expression, bool> eq =
ExpressionEqualityComparer.Instance.Equals;
Expression<Func<User, bool>> expression = a => a.Email == "a";
_repo.Setup(a => a.Single(It.Is<Expression<Func<User,bool>>>(l => eq(l,expression))).Returns(unregisteredTestUser);
At any rate the core problem is probably that comparison.
Marc Gravell's answer seems to imply using the method your using will work, but only if everything including variables in the implementation of your actual method are exactly the same and are passed in that exact same state in the call to the repository dependency.
My understanding of this is you would have to have exactly the same definition of the expression that you are using for testing and in the actual implementation this is testing.
I would try debugging and looking at each expression converted to a string (the one in your test method and the one in your implementation, and check if they are exactly the same. If they are then that theory is out the window.)
It weakens your test, but you could just check if any expression is passed in and return what you want.
Another alternative that may work for you is checking if the returns of the delegates are the same, but again this is a weaker test:
_repo.Setup(a => a.Single(It.Is<Expression<Func<User,bool>>>(l = l(unregisteredTestUser)== expression(unregisteredTestUser)))).Returns(unregisteredTestUser);
Yet another (weak) way to test it would be to pass the expression against a list and let Linq To Objects return what it may. Again your wouldn't get exactly the same behavior from linq to objects as you would from Linq2Sql or Linq2EF or anything else, but...
anyway here it is:
List<User> users = new List<User>()
{
new User { Email = "a" },
new User { Email = "b" }
};
_repo.Setup(a => a.Single(It.IsAny<Expression<Func<User, bool>>>()))
.Returns<Expression<Func<User, bool>>>(predicate => users.AsQueryable()
.Where(predicate).SingleOrDefault());
With this, whatever gets passed to the Single method, would get passed to the Where method in the list...

Different return values the first and second time with Moq

I have a test like this:
[TestCase("~/page/myaction")]
public void Page_With_Custom_Action(string path) {
// Arrange
var pathData = new Mock<IPathData>();
var pageModel = new Mock<IPageModel>();
var repository = new Mock<IPageRepository>();
var mapper = new Mock<IControllerMapper>();
var container = new Mock<IContainer>();
container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageModel.Object);
pathData.Setup(x => x.Action).Returns("myaction");
pathData.Setup(x => x.Controller).Returns("page");
var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);
// Act
var data = resolver.ResolvePath(path);
// Assert
Assert.NotNull(data);
Assert.AreEqual("myaction", data.Action);
Assert.AreEqual("page", data.Controller);
}
GetPageByUrl runs twice in my DashboardPathResolver, how can I tell Moq to return null the first time and pageModel.Object the second?
With the latest version of Moq(4.2.1312.1622), you can setup a sequence of events using SetupSequence. Here's an example:
_mockClient.SetupSequence(m => m.Connect(It.IsAny<String>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new SocketException())
.Throws(new SocketException())
.Returns(true)
.Throws(new SocketException())
.Returns(true);
Calling connect will only be successful on the third and fifth attempt otherwise an exception will be thrown.
So for your example it would just be something like:
repository.SetupSequence(x => x.GetPageByUrl<IPageModel>(virtualUrl))
.Returns(null)
.Returns(pageModel.Object);
The existing answers are great, but I thought I'd throw in my alternative which just uses System.Collections.Generic.Queue and doesn't require any special knowledge of the mocking framework - since I didn't have any when I wrote it! :)
var pageModel = new Mock<IPageModel>();
IPageModel pageModelNull = null;
var pageModels = new Queue<IPageModel>();
pageModels.Enqueue(pageModelNull);
pageModels.Enqueue(pageModel.Object);
Then...
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(pageModels.Dequeue);
Now you can use SetupSequence. See this post.
var mock = new Mock<IFoo>();
mock.SetupSequence(f => f.GetCount())
.Returns(3) // will be returned on 1st invocation
.Returns(2) // will be returned on 2nd invocation
.Returns(1) // will be returned on 3rd invocation
.Returns(0) // will be returned on 4th invocation
.Throws(new InvalidOperationException()); // will be thrown on 5th invocation
You can use a callback when setting up your mock object. Take a look at the example from the Moq Wiki (https://github.com/Moq/moq4/wiki/Quickstart).
// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls)
.Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());
Your setup might look like this:
var pageObject = pageModel.Object;
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageObject).Callback(() =>
{
// assign new value for second call
pageObject = new PageModel();
});
Adding a callback did not work for me, I used this approach instead http://haacked.com/archive/2009/09/29/moq-sequences.aspx and I ended up with a test like this:
[TestCase("~/page/myaction")]
[TestCase("~/page/myaction/")]
public void Page_With_Custom_Action(string virtualUrl) {
// Arrange
var pathData = new Mock<IPathData>();
var pageModel = new Mock<IPageModel>();
var repository = new Mock<IPageRepository>();
var mapper = new Mock<IControllerMapper>();
var container = new Mock<IContainer>();
container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);
repository.Setup(x => x.GetPageByUrl<IPageModel>(virtualUrl)).ReturnsInOrder(null, pageModel.Object);
pathData.Setup(x => x.Action).Returns("myaction");
pathData.Setup(x => x.Controller).Returns("page");
var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);
// Act
var data = resolver.ResolvePath(virtualUrl);
// Assert
Assert.NotNull(data);
Assert.AreEqual("myaction", data.Action);
Assert.AreEqual("page", data.Controller);
}
The accepted answer, as well as the SetupSequence answer, handles returning constants.
Returns() has some useful overloads where you can return a value based on the parameters that were sent to the mocked method. Based on the solution given in the accepted answer, here is another extension method for those overloads.
public static class MoqExtensions
{
public static IReturnsResult<TMock> ReturnsInOrder<TMock, TResult, T1>(this ISetup<TMock, TResult> setup, params Func<T1, TResult>[] valueFunctions)
where TMock : class
{
var queue = new Queue<Func<T1, TResult>>(valueFunctions);
return setup.Returns<T1>(arg => queue.Dequeue()(arg));
}
}
Unfortunately, using the method requires you to specify some template parameters, but the result is still quite readable.
repository
.Setup(x => x.GetPageByUrl<IPageModel>(path))
.ReturnsInOrder(new Func<string, IPageModel>[]
{
p => null, // Here, the return value can depend on the path parameter
p => pageModel.Object,
});
Create overloads for the extension method with multiple parameters (T2, T3, etc) if needed.
Reached here for the same kind of problem with slightly different requirement.
I need to get different return values from mock based in different input values and found solution which IMO more readable as it uses Moq's declarative syntax (linq to Mocks).
public interface IDataAccess
{
DbValue GetFromDb(int accountId);
}
var dataAccessMock = Mock.Of<IDataAccess>
(da => da.GetFromDb(It.Is<int>(acctId => acctId == 0)) == new Account { AccountStatus = AccountStatus.None }
&& da.GetFromDb(It.Is<int>(acctId => acctId == 1)) == new DbValue { AccountStatus = AccountStatus.InActive }
&& da.GetFromDb(It.Is<int>(acctId => acctId == 2)) == new DbValue { AccountStatus = AccountStatus.Deleted });
var result1 = dataAccessMock.GetFromDb(0); // returns DbValue of "None" AccountStatus
var result2 = dataAccessMock.GetFromDb(1); // returns DbValue of "InActive" AccountStatus
var result3 = dataAccessMock.GetFromDb(2); // returns DbValue of "Deleted" AccountStatus
We can simply declare one variable with int as a datatype. initialize it to zero, and then increase it's value as follows:
int firstTime = 0;
repository.Setup(_ => _.GetPageByUrl<IPageModel>(path)).Returns(() =>
{
if (firstTime == 0)
{
firstTime = 1;
return null;
}
else if(firstTime == 1)
{
firstTime = 2;
return pageModel.Object;
}
else
{
return null;
}
});
In some cases one needs to have the called function return different types of data based on conditions you cannot impose via the function itself. If the function accepts parameters then those can be used as conditionals to get different data.
In my case, I had a webapi call which I need to mock; earlier it was working out fine based on the input parameter, however one fine day, those parameters were converted to request headers. So since I couldn't provide a callback (no function parameters) so came up with another approach as follows
[Earlier one, when API had parameters]
this.mockedMasterAPICalls.Setup(m => m.GetCountries(It.Is<int>(ou => ou == 2), It.Is<int>(lan => lan == 1))).Returns(Task.FromResult(countryResponse));
[New one, when API had headers... The headers were getting injected into another dictionary of the API caller]
this.mockedMasterAPICalls.Setup(m => m.RequestHeaders).Returns(new Dictionary<string, string>());
this.mockedMasterAPICalls.Setup(m => m.GetCountries()).Returns(() =>
{
if (this.mockedMasterAPICalls.Object.RequestHeaders[GlobalConstants.HeaderOUInstance] == "2")
return Task.FromResult(countryResponse);
else return Task.FromResult(new GetCountryResponse() { Countries = null });
});
Note the use of the mocked object itself to make any decisions required

Verifying a specific parameter with Moq

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
var messageServiceClientMock = new Mock<IMessageServiceClient>();
var queueableMessage = CreateSingleQueueableMessage();
var message = queueableMessage[0];
var xml = QueueableMessageAsXml(queueableMessage);
messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(xml)).Verifiable();
//messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();
var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(essageServiceClientMock.Object);
var loggerStub = new Mock<ILogger>();
var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});
//messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(xml), Times.Once());
messageServiceClientMock.Verify();
}
I'm starting using Moq and struggling a bit.
I'm trying to verify that messageServiceClient is receiving the right parameter, which is an XmlElement, but I can't find any way to make it work. It works only when I don't check a particular value.
Any ideas?
Partial answer:
I've found a way to test that the xml sent to the proxy is correct, but I still don't think it's the right way to do it.
public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
var messageServiceClientMock = new Mock<IMessageServiceClient>();
messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();
var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(messageServiceClientMock.Object);
var loggerStub = new Mock<ILogger>();
var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
var message = CreateMessage();
client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});
messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(It.Is<XmlElement>(xmlElement => XMLDeserializer<QueueableMessage>.Deserialize(xmlElement).Messages.Contains(message))), Times.Once());
}
By the way, how could I extract the expression from the Verify call?
If the verification logic is non-trivial, it will be messy to write a large lambda method (as your example shows). You could put all the test statements in a separate method, but I don't like to do this because it disrupts the flow of reading the test code.
Another option is to use a callback on the Setup call to store the value that was passed into the mocked method, and then write standard Assert methods to validate it. For example:
// Arrange
MyObject saveObject;
mock.Setup(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()))
.Callback<int, MyObject>((i, obj) => saveObject = obj)
.Returns("xyzzy");
// Act
// ...
// Assert
// Verify Method was called once only
mock.Verify(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()), Times.Once());
// Assert about saveObject
Assert.That(saveObject.TheProperty, Is.EqualTo(2));
I've been verifying calls in the same manner - I believe it is the right way to do it.
mockSomething.Verify(ms => ms.Method(
It.IsAny<int>(),
It.Is<MyObject>(mo => mo.Id == 5 && mo.description == "test")
), Times.Once());
If your lambda expression becomes unwieldy, you could create a function that takes MyObject as input and outputs true/false...
mockSomething.Verify(ms => ms.Method(
It.IsAny<int>(),
It.Is<MyObject>(mo => MyObjectFunc(mo))
), Times.Once());
private bool MyObjectFunc(MyObject myObject)
{
return myObject.Id == 5 && myObject.description == "test";
}
Also, be aware of a bug with Mock where the error message states that the method was called multiple times when it wasn't called at all. They might have fixed it by now - but if you see that message you might consider verifying that the method was actually called.
EDIT: Here is an example of calling verify multiple times for those scenarios where you want to verify that you call a function for each object in a list (for example).
foreach (var item in myList)
mockRepository.Verify(mr => mr.Update(
It.Is<MyObject>(i => i.Id == item.Id && i.LastUpdated == item.LastUpdated),
Times.Once());
Same approach for setup...
foreach (var item in myList) {
var stuff = ... // some result specific to the item
this.mockRepository
.Setup(mr => mr.GetStuff(item.itemId))
.Returns(stuff);
}
So each time GetStuff is called for that itemId, it will return stuff specific to that item. Alternatively, you could use a function that takes itemId as input and returns stuff.
this.mockRepository
.Setup(mr => mr.GetStuff(It.IsAny<int>()))
.Returns((int id) => SomeFunctionThatReturnsStuff(id));
One other method I saw on a blog some time back (Phil Haack perhaps?) had setup returning from some kind of dequeue object - each time the function was called it would pull an item from a queue.
A simpler way would be to do:
ObjectA.Verify(
a => a.Execute(
It.Is<Params>(p => p.Id == 7)
)
);
I believe that the problem in the fact that Moq will check for equality. And, since XmlElement does not override Equals, it's implementation will check for reference equality.
Can't you use a custom object, so you can override equals?
Had one of these as well, but the parameter of the action was an interface with no public properties. Ended up using It.Is() with a seperate method and within this method had to do some mocking of the interface
public interface IQuery
{
IQuery SetSomeFields(string info);
}
void DoSomeQuerying(Action<IQuery> queryThing);
mockedObject.Setup(m => m.DoSomeQuerying(It.Is<Action<IQuery>>(q => MyCheckingMethod(q)));
private bool MyCheckingMethod(Action<IQuery> queryAction)
{
var mockQuery = new Mock<IQuery>();
mockQuery.Setup(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition())
queryAction.Invoke(mockQuery.Object);
mockQuery.Verify(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition(), Times.Once)
return true
}

Categories

Resources