I have a Setup.Callback()
action that's not being called in VB.NET. It works as expected in C#. The code conversion is correct.
VB.NET
Private Function CreateFriendEditViewModel() As IFriendEditViewModel
Dim oWrapper As FriendWrapper
Dim oFriend As [Friend]
Dim oMock As Mock(Of IFriendEditViewModel)
oMock = New Mock(Of IFriendEditViewModel)
oMock.
Setup(Sub(Vm) Vm.Load(It.IsAny(Of Integer))).
Callback(Of Integer?)(Sub(FriendId)
oFriend = New [Friend] With {.Id = FriendId.Value}
oWrapper = New FriendWrapper(oFriend)
oMock.
Setup(Function(Vm) Vm.Friend).
Returns(oWrapper)
End Sub)
Me.FriendEditViewModelMocks.Add(oMock)
Return oMock.Object
End Function
C#
private IFriendEditViewModel CreateFriendEditViewModel()
{
var friendEditViewModelMock = new Mock<IFriendEditViewModel>();
friendEditViewModelMock
.Setup(vm => vm.Load(It.IsAny<int>()))
.Callback<int?>(friendId =>
{
friendEditViewModelMock
.Setup(vm => vm.Friend)
.Returns(new FriendWrapper(new Friend { Id = friendId.Value }));
});
_friendEditViewModelMocks.Add(friendEditViewModelMock);
return friendEditViewModelMock.Object;
}
Note that it works in VB.NET when I change the Nullable(Of Integer)
type to Integer
.
While grabbing at straws, I tried this slight variation:
oMock.
Setup(Function(Vm) Vm.Friend).
Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))
...but it didn't help.
Neither did any of these three Q&As shed light on the situation:
I'm very much a beginner at Moq, so this has got me befuddled.
Can anyone spot what's going wrong here? Why isn't my callback being called, and why is this failure occurring only in VB.NET?
--UPDATE--
I had a look at the IL (via JustDecompile) for each of these four scenarios:
- VB.NET using type
Integer
(succeeds)
Callback(Of Integer)(Sub(FriendId)
oMock.
Setup(Function(Vm) Vm.Friend).
Returns(New FriendWrapper(New [Friend] With {.Id = FriendId}))
End Sub)
.method private instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
.locals init (
[0] class FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0' $VB$Closure_0,
[1] class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel,
[2] class [System.Core]System.Linq.Expressions.ParameterExpression V_2
)
IL_0000: nop
IL_0001: newobj instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::.ctor()
IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_0012: ldloc.0
IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel
IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0022: ldstr "Vm"
IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
IL_002c: stloc.2
IL_002d: ldloc.2
IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel::Load(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
IL_003d: ldc.i4.1
IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
IL_0043: dup
IL_0044: ldc.i4.0
IL_0045: ldnull
IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
IL_0055: ldc.i4.0
IL_0056: newarr [System.Core]System.Linq.Expressions.Expression
IL_005b: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_0060: ldtoken valuetype [mscorlib]System.Nullable`1<int32>
IL_0065: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_006a: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::ConvertChecked(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Type)
IL_006f: stelem.ref
IL_0070: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_0075: ldc.i4.1
IL_0076: newarr [System.Core]System.Linq.Expressions.ParameterExpression
IL_007b: dup
IL_007c: ldc.i4.0
IL_007d: ldloc.2
IL_007e: stelem.ref
IL_007f: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
IL_0084: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
IL_0089: ldloc.0
IL_008a: ldftn instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::_Lambda$__0(int32)
IL_0090: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int)
IL_0095: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<int32>(class [mscorlib]System.Action`1<int32>)
IL_009a: pop
IL_009b: ldarg.0
IL_009c: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> FriendStorage.UI.Tests.ViewModels.MainViewModelTests::FriendEditViewModelMocks
IL_00a1: ldloc.0
IL_00a2: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_00a7: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>::Add(!0)
IL_00ac: nop
IL_00ad: ldloc.0
IL_00ae: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_00b3: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::get_Object()
IL_00b8: stloc.1
IL_00b9: br.s IL_00bb
IL_00bb: ldloc.1
IL_00bc: ret
}
- VB.NET using type
Integer?
(fails)
Callback(Of Integer?)(Sub(FriendId)
oMock.
Setup(Function(Vm) Vm.Friend).
Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))
End Sub)
.method private instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
.locals init (
[0] class FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0' $VB$Closure_0,
[1] class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel,
[2] class [System.Core]System.Linq.Expressions.ParameterExpression V_2
)
IL_0000: nop
IL_0001: newobj instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::.ctor()
IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_0012: ldloc.0
IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel
IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0022: ldstr "Vm"
IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
IL_002c: stloc.2
IL_002d: ldloc.2
IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel::Load(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
IL_003d: ldc.i4.1
IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
IL_0043: dup
IL_0044: ldc.i4.0
IL_0045: ldnull
IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
IL_0055: ldc.i4.0
IL_0056: newarr [System.Core]System.Linq.Expressions.Expression
IL_005b: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_0060: ldtoken valuetype [mscorlib]System.Nullable`1<int32>
IL_0065: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_006a: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::ConvertChecked(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Type)
IL_006f: stelem.ref
IL_0070: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_0075: ldc.i4.1
IL_0076: newarr [System.Core]System.Linq.Expressions.ParameterExpression
IL_007b: dup
IL_007c: ldc.i4.0
IL_007d: ldloc.2
IL_007e: stelem.ref
IL_007f: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
IL_0084: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
IL_0089: ldloc.0
IL_008a: ldftn instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::_Lambda$__0(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0090: newobj instance void class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>::.ctor(object, native int)
IL_0095: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<valuetype [mscorlib]System.Nullable`1<int32>>(class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>)
IL_009a: pop
IL_009b: ldarg.0
IL_009c: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> FriendStorage.UI.Tests.ViewModels.MainViewModelTests::FriendEditViewModelMocks
IL_00a1: ldloc.0
IL_00a2: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_00a7: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>::Add(!0)
IL_00ac: nop
IL_00ad: ldloc.0
IL_00ae: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
IL_00b3: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::get_Object()
IL_00b8: stloc.1
IL_00b9: br.s IL_00bb
IL_00bb: ldloc.1
IL_00bc: ret
}
- C# using type
int
(succeeds)
.Callback<int>(friendId =>
{
friendEditViewModelMock
.Setup(vm => vm.Friend)
.Returns(new FriendWrapper(new Friend { Id = friendId }));
});
.method private hidebysig instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
.locals init (
[0] class FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0' 'CS$<>8__locals0',
[1] class [System.Core]System.Linq.Expressions.ParameterExpression V_1,
[2] class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel V_2
)
IL_0000: newobj instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::.ctor()
IL_0005: stloc.0
IL_0006: nop
IL_0007: ldloc.0
IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::.ctor()
IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_0012: ldloc.0
IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel
IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0022: ldstr "vm"
IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
IL_002c: stloc.1
IL_002d: ldloc.1
IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel::Load(int32)
IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
IL_003d: ldc.i4.1
IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
IL_0043: dup
IL_0044: ldc.i4.0
IL_0045: ldnull
IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
IL_0055: call class [System.Core]System.Linq.Expressions.Expression[] [mscorlib]System.Array::Empty<class [System.Core]System.Linq.Expressions.Expression>()
IL_005a: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_005f: stelem.ref
IL_0060: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_0065: ldc.i4.1
IL_0066: newarr [System.Core]System.Linq.Expressions.ParameterExpression
IL_006b: dup
IL_006c: ldc.i4.0
IL_006d: ldloc.1
IL_006e: stelem.ref
IL_006f: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
IL_0074: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
IL_0079: ldloc.0
IL_007a: ldftn instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::'<CreateFriendEditViewModel>b__1'(int32)
IL_0080: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int)
IL_0085: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<int32>(class [mscorlib]System.Action`1<int32>)
IL_008a: pop
IL_008b: ldarg.0
IL_008c: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> FriendStorage.UITests.ViewModel.MainViewModelTests::_friendEditViewModelMocks
IL_0091: ldloc.0
IL_0092: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_0097: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>::Add(!0)
IL_009c: nop
IL_009d: ldloc.0
IL_009e: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_00a3: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::get_Object()
IL_00a8: stloc.2
IL_00a9: br.s IL_00ab
IL_00ab: ldloc.2
IL_00ac: ret
}
- C# using type
int?
(succeeds)
.Callback<int?>(friendId =>
{
friendEditViewModelMock
.Setup(vm => vm.Friend)
.Returns(new FriendWrapper(new Friend { Id = friendId.Value }));
});
.method private hidebysig instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
.locals init (
[0] class FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0' 'CS$<>8__locals0',
[1] class [System.Core]System.Linq.Expressions.ParameterExpression V_1,
[2] class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel V_2
)
IL_0000: newobj instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::.ctor()
IL_0005: stloc.0
IL_0006: nop
IL_0007: ldloc.0
IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::.ctor()
IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_0012: ldloc.0
IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel
IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0022: ldstr "vm"
IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
IL_002c: stloc.1
IL_002d: ldloc.1
IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel::Load(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
IL_003d: ldc.i4.1
IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
IL_0043: dup
IL_0044: ldc.i4.0
IL_0045: ldnull
IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
IL_0055: call class [System.Core]System.Linq.Expressions.Expression[] [mscorlib]System.Array::Empty<class [System.Core]System.Linq.Expressions.Expression>()
IL_005a: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_005f: ldtoken valuetype [mscorlib]System.Nullable`1<int32>
IL_0064: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0069: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::Convert(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Type)
IL_006e: stelem.ref
IL_006f: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
IL_0074: ldc.i4.1
IL_0075: newarr [System.Core]System.Linq.Expressions.ParameterExpression
IL_007a: dup
IL_007b: ldc.i4.0
IL_007c: ldloc.1
IL_007d: stelem.ref
IL_007e: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
IL_0083: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
IL_0088: ldloc.0
IL_0089: ldftn instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::'<CreateFriendEditViewModel>b__1'(valuetype [mscorlib]System.Nullable`1<int32>)
IL_008f: newobj instance void class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>::.ctor(object, native int)
IL_0094: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<valuetype [mscorlib]System.Nullable`1<int32>>(class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>)
IL_0099: pop
IL_009a: ldarg.0
IL_009b: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> FriendStorage.UITests.ViewModel.MainViewModelTests::_friendEditViewModelMocks
IL_00a0: ldloc.0
IL_00a1: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_00a6: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>::Add(!0)
IL_00ab: nop
IL_00ac: ldloc.0
IL_00ad: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
IL_00b2: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::get_Object()
IL_00b7: stloc.2
IL_00b8: br.s IL_00ba
IL_00ba: ldloc.2
IL_00bb: ret
}
I had hoped something would jump out and be easy to spot, but unfortunately IL is still very much a mystery to me. That said, I do notice a significant difference between the VB and C# versions. In fact, there's even quite a difference between the C# int/int?
versions. Not so much between Integer/Integer?
in VB.
As a safety check, I implemented a Try/Catch
as well:
Callback(Of Integer?)(Sub(FriendId)
Try
oMock.
Setup(Function(Vm) Vm.Friend).
Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End Sub)
Still no change. The callback simply isn't called when using a Nullable(Of Integer)
in VB. I'd love to set a breakpoint somewhere in there, but it won't do any good if execution never reaches that code block.
This is a show-stopper for my current project, so I'm calling in all experts.
OK, got it.
Here's the IFriendEditViewModel
signature:
Public Interface IFriendEditViewModel
Sub Load(FriendId As Integer?)
ReadOnly Property [Friend] As FriendWrapper
End Interface
...and here's the original setup/callback again:
Private Function CreateFriendEditViewModel() As IFriendEditViewModel
Dim oMock = New Mock(Of IFriendEditViewModel)
oMock.
Setup(Sub(Vm) Vm.Load(It.IsAny(Of Integer))).
Callback(Of Integer?)(Sub(FriendId)
oMock.
Setup(Function(Vm) Vm.Friend).
Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))
End Sub)
Me.FriendEditViewModelMocks.Add(oMock)
Return oMock.Object
End Function
See the problem? The Vm.Load()
method takes a Nullable(Of Integer)
. I'd missed this little detail earlier; I'm converting from C#, which apparently allows the mixing of parameter types in this case. Contrary to one's expectations, this builds and runs just fine:
private IFriendEditViewModel CreateFriendEditViewModel()
{
var friendEditViewModelMock = new Mock<IFriendEditViewModel>();
friendEditViewModelMock
.Setup(vm => vm.Load(It.IsAny<int>())) // <== Oops!
.Callback<int?>(friendId =>
{
friendEditViewModelMock
.Setup(vm => vm.Friend)
.Returns(new FriendWrapper(new Friend { Id = friendId.Value }));
});
_friendEditViewModelMocks.Add(friendEditViewModelMock);
return friendEditViewModelMock.Object;
}
So, I just changed the parameter for my setup to this:
Setup(Sub(Vm) Vm.Load(It.IsAny(Of Integer?)))
...and it sailed right through. The callback is called as expected.
In fact, I'm not entirely sure I wouldn't call this a bug in the C# compiler.