Jon*_*nny 6 c# unit-testing pointers unsafe moq
是否可以使用Moq来模拟不安全的界面?例如我有(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();
...
}
Run Code Online (Sandbox Code Playgroud)
但是,我不能使用不安全的类型作为类型参数,我得到错误:
Error 1 The type 'int*' may not be used as a type argument
Run Code Online (Sandbox Code Playgroud)
是否可以在不使用类型参数的情况下设置模拟以避免此问题?
(我知道显而易见的解决方案是不使用不安全的接口,我想知道是否有一个解决方案可以使用不安全的接口.)
编辑/更新:可以使用存根类,但我想避免使用Moq,因为Moq提供了相当少的详细代码.
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();
}
...
}
Run Code Online (Sandbox Code Playgroud)
快速回答如果您的类型在方法签名中具有指针类型,则不可能.
您看到的错误是因为您不能将指针用作类型参数.实际上,在C#规范中,您将在第4.4.1节(类型参数)中找到:
在不安全的代码中,type-argument可能不是指针类型.
您可以通过更改代码以期望特定指针来避免此特定错误:
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));
Run Code Online (Sandbox Code Playgroud)
但是,Moq在Setup
调用中失败,因为它试图为参数创建一个Matcher
对象(用于匹配设置和调用),该参数使用参数的类型作为类型参数.这导致与上述相同的错误.传递Match
通过Match.Create
或It.Is
方法创建的自己的对象将不起作用,因为这些方法也采用类型参数.
如果省略Setup
调用,利用松散的模拟行为,那么Moq会Verify
因为同样的问题而在调用中失败.它正在尝试根据参数参数的类型创建一个对象,以便它可以将记录的调用与传入的表达式进行匹配.
Moq还提供了一种It
在提供类之前匹配参数的旧方法,其中您使用Matcher
属性标记方法:
[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;
}
Run Code Online (Sandbox Code Playgroud)
这似乎可行,但它失败并出现异常:
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)
我无法弄清楚它来自何处或如何规避它,所以这也是一个死胡同.
这里最好的情况是,如果你可以改变int*
到IntPtr
,这通常可以嘲笑.如果您无法更改类型,那么根据您要查看的内容,您可以创建存根对象而不是依赖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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的测试中:
int* any = stackalloc int[4];
int* other = stackalloc int[4];
var stubMyUnsafeInterface = new StubMyUnsafeInterface(any);
stubMyUnsafeInterface.DoWork(any); // passes
stubMyUnsafeInterface.DoWork(other); // fails
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
792 次 |
最近记录: |