I have a class that is a consumer of the strategy pattern that I would like to unit test. It has a dependency on an IResolver type class that returns some instance of an ICalculator type class. So I need a Moq object that represents the resolver & when called, returns another Moq object that represents the calculator. I have this test below:
public void UpperScoreManager_AddScoring_UpdatesScoreCorrectly()
{
var expectedScore = 10;
var mockCaluclator = new Mock < IScoreCategoryCalculator > ();
mockCaluclator.Setup(c => c.CalculateScore(It.IsAny < DiceSet > ()))
.Returns(expectedScore);
var mockResolver = new Mock < IScoreCategoryCalculatorResolver > ();
mockResolver.Setup(r => r.Resolve(It.IsAny < ScoreCategories > ()))
.Returns(mockCaluclator.Object);
var manager = new Managers.ScoreManager.UpperScoreManager.UpperScoreManager(mockResolver.Object);
manager.AddScoring(ScoreCategories.Aces, DiceSet.Create(new int[] { 1, 2, 3, 4, 5 }));
Assert.Equal(expectedScore, manager.Score);
}
And here is the function being tested
public void AddScoring(ScoreCategories category, DiceSet diceSet)
{
IScoreCategoryCalculator scoreCalculator = _scoreCalculatorResolver.Resolve(category);
Score += scoreCalculator.CalculateScore(diceSet);
}
The unit test fails due to some error with the Moq setup:
System.ArgumentException : Object of type 'Yahtzee.Core.Enums.ScoreCategories' cannot be converted to type 'Yahtzee.Core.Interfaces.IScoreCategoryCalculator'
I don't understand this error (I don't receive this until I actually run the unit test). When I debug the test, the first line of my function under test works correctly
IScoreCategoryCalculator scoreCalculator = _scoreCalculatorResolver.Resolve(category);
So my mock resolver is resolving some IScoreCategoryCalculator. The next line, however, is where the failure occurs. If I do a QuickWatch on that line in Visual Studio I can see this:
Any idea what I'm doing incorrectly here? Can Moq return another Moq object?
EDIT The interfaces being mocked look as so:
public interface IScoreCategoryCalculator
{
ScoreCategories Type { get; }
int CalculateScore(DiceSet diceSet);
}
public interface IScoreCategoryCalculatorResolver
{
IScoreCategoryCalculator Resolve(ScoreCategories scoreCategory);
}
EDIT 2 Showing full stack
Stack Trace: RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast) RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr) MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) Delegate.DynamicInvokeImpl(Object[] args) Delegate.DynamicInvoke(Object[] args) Extensions.InvokePreserveStack(Delegate del, Object[] args) ReturnLazyValueResponse.RespondTo(Invocation invocation) MethodCall.Execute(Invocation invocation) FindAndExecuteMatchingSetup.Handle(Invocation invocation, Mock mock) IInterceptor.Intercept(Invocation invocation) Interceptor.Intercept(IInvocation invocation) AbstractInvocation.Proceed() IScoreCategoryCalculatorResolverProxy.Resolve(ScoreCategories scoreCategory) UpperScoreManager.AddScoring(ScoreCategories category, DiceSet diceSet) line 32 UpperScoreManagerTests.UpperScoreManager_AddScoring_UpdatesScoreCorrectly() line 18
