Using Moq to mock an unsafe interface

Can Moq be used to mock an unsafe interface? For example, I have (MCVE):

[TestClass] public class UnitTest1 { [TestMethod] public unsafe void TestMethod1() { Mock<IMyUnsafeInterface> mockDependency = new Mock<IMyUnsafeInterface>(); mockDependency.Setup(i => i.DoWork(It.IsAny<int*>())); // error on this line systemUnderTest.Dependency = mockDependency.Object; ... } } public unsafe interface IMyUnsafeInterface { void DoWork(int* intPtr); byte* MethodNotRelevantToThisTest1(byte* bytePtr); ComplexObject MethodNotRelevantToThisTest2(); ... } 

However, I cannot use an unsafe type as a type parameter, and I get an error:

 Error 1 The type 'int*' may not be used as a type argument 

Is it possible to configure mocks without using a type parameter to avoid this problem?

(I know that the obvious solution is not to use an unsafe interface, I wonder if there is a solution that works with unsafe interfaces.)

Edit / Update : you can use the stub class, but I would like to avoid this if you can use Moq, since Moq provides much less verbose code.

 public unsafe class MyUnsafeClass : IMyUnsafeInterface { public void DoWork(int* intPtr) { // Do something } public byte* MethodNotRelevantToThisTest1(byte* bytePtr) { throw new NotImplementedException(); } public ComplexObject MethodNotRelevantToThisTest2() { throw new NotImplementedException(); } ... } 
+6
source share
2 answers

Quick answer Impossible if your type has pointer types in method signatures.


The error you see is that you cannot use a pointer as a type argument. Indeed, in the C # specification you will 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 to call Setup because it tries to create a Matcher object (used to map settings for invocations) for an argument that uses the argument type as a type parameter. This results in the same error as above. Passing your own Match object created using Match.Create or It.Is methods will not work because these methods also take a type argument.

If you omit the Setup call using the missing mocking behavior, Moq fails in the Verify call due to the same problem. It tries to create an object based on the argument parameter type so that it can match the recorded call with the expression passed.

Moq also provides an older method for matching arguments before the It class was provided, where you mark a method with the 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 to work, but the failure is ruled out:

  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 understand where it comes from or how to get around it, so there’s a dead end too.

The best case here would be if you could change int* to IntPtr , which can be mocked in the usual way. If you cannot change the type, then depending on what you want to test, you can 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 
+5
source

To avoid this, you can try the concept of the Wrapper class. You can simply wrap your original class or interface. And after that you can use your original function inside the function of the Wrapper class. As shown below -

 //Wrapper class public class MyWrapperClass { public YourReturnType MyFunction() { OriginalClass obj = new OriginalClass(); //And inside this function call your original function return obj.OriginalFunction(); } } 

The Wrapper class wraps the original type, and we can use the / mock source object to suit our needs.

If you do not know the concept of the Wrapper class, first understand its concept.

http://www.c-sharpcorner.com/Blogs/12038/wrapper-class-in-C-Sharp.aspx

-1
source

Source: https://habr.com/ru/post/974683/


All Articles