Putting aside the MockRepository for the moment, I've created a class that inherits from Mock
to provide the functionality you're after. Firstly, the usage (XUnit syntax):
[Fact]
public void SomeTest()
{
var mock = new Mock2<IDependency>();
var sut = new Sut(mock.Object);
mock.SetupAndExpect(d => d.DoSomething(It.IsAny<string>(), It.IsAny<long>()),Times.Once).Returns(3);
mock.SetupAndExpect(d => d.DoSomethingNoReturn(It.IsAny<string>()), Times.Once);
mock.SetupAndExpect(d => d.DoSomethingNoReturn(It.IsAny<string>()), Times.Once);
sut.CallDoSomething();
mock.VerifyAllExpectations();
}
The SetupAndExpect
method is a replacement for Setup
that allows Times
to be passed. The VerifyAllExpectations
is an equivalent to VerifyAll
. You could fiddle around with these names if you wanted.
The Mock2
class stores the expression
and times
passed to SetupAndExpect
ready for later use during VerifyAllExpectations
.
Before I show the Mock2
code and talk about a MockRepository
solution, a word of explanation about the wordiness. It was fairly easy to get it working for mocked methods with no return value as the expressions all have a type that is generic over the mocked type. For methods with a return value, however, the underlying verification to be called is Mock.Verify<TResult>(...)
. In order to be able to bind to the correctly closed method during VerifyAllExpectations
I ended up using reflection. I'm sure modifying Mock itself to put this functionality in would allow for a less hacky solution.
Now, back to the repository: My thoughts are to modify Mock2
so that rather than inheriting from Mock
, it takes an instance of Mock
as a constructor parameter and uses that to call Setup
and Verify
. Then you could write a new extension method on MockRepository
(Create2
??) that calls the original MockRepository.Create
and passes the created Mock
instance to the constructor of a Mock2
instance, which it then returns.
A final alternative to this is to add SetupAndExpect
and VerifyAllExpectations
as extension methods on Mock
. However, the storage of the expectation information would then probably have to be in some static state and face clean up issues.
Here's the Mock2
code:
public class Mock2<T> : Mock<T> where T:class
{
private readonly Dictionary<Type, List<Tuple<Expression,Func<Times>>>> _resultTypeKeyedVerifications =
new Dictionary<Type, List<Tuple<Expression, Func<Times>>>>();
private readonly List<Tuple<Expression<Action<T>>, Func<Times>>> _noReturnTypeVerifications =
new List<Tuple<Expression<Action<T>>, Func<Times>>>();
public ISetup<T, TResult> SetupAndExpect<TResult>(Expression<Func<T, TResult>> expression, Func<Times> times)
{
// Store the expression for verifying in VerifyAllExpectations
var verificationsForType = GetVerificationsForType(typeof(TResult));
verificationsForType.Add(new Tuple<Expression, Func<Times>>(expression, times));
// Continue with normal setup
return Setup(expression);
}
public ISetup<T> SetupAndExpect(Expression<Action<T>> expression, Func<Times> times)
{
_noReturnTypeVerifications.Add(new Tuple<Expression<Action<T>>, Func<Times>>(expression, times));
return Setup(expression);
}
private List<Tuple<Expression, Func<Times>>> GetVerificationsForType(Type type)
{
// Simply gets a list of verification info for a particular return type,
// creating it and putting it in the dictionary if it doesn't exist.
if (!_resultTypeKeyedVerifications.ContainsKey(type))
{
var verificationsForType = new List<Tuple<Expression, Func<Times>>>();
_resultTypeKeyedVerifications.Add(type, verificationsForType);
}
return _resultTypeKeyedVerifications[type];
}
/// <summary>
/// Use this instead of VerifyAll for setups perfomed using SetupAndRespect
/// </summary>
public void VerifyAllExpectations()
{
VerifyAllWithoutReturnType();
VerifyAllWithReturnType();
}
private void VerifyAllWithoutReturnType()
{
foreach (var noReturnTypeVerification in _noReturnTypeVerifications)
{
var expression = noReturnTypeVerification.Item1;
var times = noReturnTypeVerification.Item2;
Verify(expression, times);
}
}
private void VerifyAllWithReturnType()
{
foreach (var typeAndVerifications in _resultTypeKeyedVerifications)
{
var returnType = typeAndVerifications.Key;
var verifications = typeAndVerifications.Value;
foreach (var verification in verifications)
{
var expression = verification.Item1;
var times = verification.Item2;
// Use reflection to find the Verify method that takes an Expression of Func of T, TResult
var verifyFuncMethod = GetType()
.GetMethods(BindingFlags.Instance | BindingFlags.Public)
.Single(IsVerifyMethodForReturnTypeAndFuncOfTimes)
.MakeGenericMethod(returnType);
// Equivalent to Verify(expression, times)
verifyFuncMethod.Invoke(this, new object[] {expression, times});
}
}
}
private static bool IsVerifyMethodForReturnTypeAndFuncOfTimes(MethodInfo m)
{
if (m.Name != "Verify") return false;
// Look for the single overload with two funcs, which is the one we want
// as we're looking at verifications for functions, not actions, and the
// overload we're looking for takes a Func<Times> as the second parameter
var parameters = m.GetParameters();
return parameters.Length == 2
&& parameters[0] // expression
.ParameterType // Expression
.GenericTypeArguments[0] // Func
.Name == "Func`2"
&& parameters[1] // times
.ParameterType // Func
.Name == "Func`1";
}
}
Final warnings: This is only lightly tested and not tested concurrently. It doesn't have an equivalent to the overload of Verify
that takes Times
rather than Func<Times>
. There are probably some better names for the methods and/or reasons why this is all generally a bad idea in the first place.
I hope it's of some use to you or someone!