Quick answer It's not possible if your type has pointer types in method signatures.
The error you're seeing is because you cannot use a pointer as a type argument. Indeed, in the C# specification you'll find in section 4.4.1 (Type Arguments):
In unsafe code, a type-argument may not be a pointer type.
You can avoid this particular error by changing your code to expect a specific pointer:
Mock<IMyUnsafeInterface> mockDependency = new Mock<IMyUnsafeInterface>();
mockDependency.Setup(i => i.DoWork(any));
// use the mock
mockDependency.Object.DoWork(any);
mockDependency.Verify(p => p.DoWork(any));
However, Moq fails in the Setup
call because it's trying to create a Matcher
object (used to match setups to invocations) for the argument, which uses the argument's type as a type parameter. This results in the same error as above. Passing your own Match
object created via Match.Create
or It.Is
methods won't work because these methods take a type argument as well.
If you omit the Setup
call, taking advantage of the loose mocking behavior, then Moq fails in the Verify
call because of the same problem. It's trying to create an object based on the type of the argument parameter so it can match a recorded call with the expression being passed in.
Moq also provides an older method of matching arguments before the It
class was provided, where you mark a method with a Matcher
attribute:
[Test]
public unsafe void TestMethod1()
{
int* any = stackalloc int[4];
Mock<IMyUnsafeInterface> mockDependency = new Mock<IMyUnsafeInterface>();
// use the mock
mockDependency.Object.DoWork(any);
mockDependency.Verify(p => p.DoWork(Is(any)));
}
[Matcher]
public static unsafe int* Is(int* expected) { return null; }
public static unsafe bool Is(int* actual, int* expected)
{
return actual == expected;
}
This seems like it would work, but it fails with an exception:
System.Security.VerificationException : Operation could destabilize the runtime.
at lambda_method(Closure)
at Moq.MatcherFactory.CreateMatcher(Expression expression, Boolean isParams)
at Moq.MethodCall..ctor(Mock mock, Func`1 condition, Expression originalExpression, MethodInfo method, Expression[] arguments)
at Moq.Mock.Verify(Mock mock, Expression`1 expression, Times times, String failMessage)
at Moq.Mock`1.Verify(Expression`1 expression)
I can't quite figure out where this is coming from or how to circumvent it, so that's a dead-end, too.
The best case here would be if you could change int*
to IntPtr
, which can be mocked normally. If you can't change the type then depending on what you're looking to verify you could make a stub object instead of relying on Moq:
unsafe class StubMyUnsafeInterface : IMyUnsafeInterface
{
readonly int* expectedIntPtr;
public StubMyUnsafeInterface(int* expectedIntPtr)
{
this.expectedIntPtr = expectedIntPtr;
}
public unsafe void DoWork(int* intPtr)
{
Assert.That(intPtr == expectedIntPtr);
}
}
Then in your test:
int* any = stackalloc int[4];
int* other = stackalloc int[4];
var stubMyUnsafeInterface = new StubMyUnsafeInterface(any);
stubMyUnsafeInterface.DoWork(any); // passes
stubMyUnsafeInterface.DoWork(other); // fails