Reputation: 9129
I'm working on some code that follows a pattern of encapsulating all arguments to a method as a "request" object and returning a "response" object. However, this has produced some problems when it comes to mocking with MOQ. For example:
public class Query : IQuery
{
public QueryResponse Execute(QueryRequest request)
{
// get the customer...
return new QueryResponse { Customer = customer };
}
}
public class QueryRequest
{
public string Key { get; set; }
}
public class QueryResponse
{
public Customer Customer { get; set; }
}
... in my test I want to stub the query to return the customer when the key is given
var customer = new Customer();
var key = "something";
var query = new Mock<ICustomerQuery>();
// I want to do something like this (but this does not work)
// i.e. I dont care what the request object that get passed is in but it must have the key value I want to give it
query.Setup(q => q.Execute(It.IsAny<QueryRequest>().Key = key))
.Returns(new QueryResponse {Customer = customer});
Is what I want possible in MOQ?
Upvotes: 14
Views: 8049
Reputation: 9931
I suspect you could do this with Custom Matchers.
From moq's QuickStart page:
// custom matchers
mock.Setup(foo => foo.Submit(IsLarge())).Throws<ArgumentException>();
...
public string IsLarge()
{
return Match.Create<string>(s => !String.IsNullOrEmpty(s) && s.Length > 100);
}
I suspect you could do a similar thing. Create a method that uses Match.Create<QueryRequest>
to match your key, e.g.
public QueryRequest CorrectKey(string key)
{
return Match.Create<QueryRequest>(qr => qr.Key == key);
}
and then
_query.Setup(q => q.Execute(CorrectKey(key))).Returns(new QueryResponse {Customer = customer});
Note: I haven't tried this code, so forgive me if it breaks entirely.
Oh, and for some mildly related self-promo: exactly this kind of complexity is what bugs me about Moq and other mocking tools. This is why I created a mocking library that allows you to check for method arguments with normal code: http://github.com/eteeselink/FakeThat. It's in the middle of a major refactoring (and renaming) process though, so you might want to hold your breath. Nevertheless, I'd be thrilled to hear what you think of it.
EDIT: Oh, @nemesv beat me to it, with a (probably) better answer. Ah well.
Upvotes: -1
Reputation: 139798
What you are looking for it the It.Is<T>
method where you can specify any matcher function (Func<T, bool>
) for the argument.
For example checking for the key:
query.Setup(q => q.Execute(It.Is<QueryRequest>(q => q.Key == key)))
.Returns(new QueryResponse {Customer = customer});
Upvotes: 25