我正在使用一个本机库,它将IntPtr返回到一个内存位置,该位置包含一个属性的值。我知道属性的类型是什么,我有一个方法来从指针所指向的内存中编组一个值(取IntPtr和属性的类型)。这个方法要么调用Marshal.ReadInt32,要么读取一系列字节并将它们转换为double,或者用Marshal.PtrToStringUni等读取字符串等。我想为这个方法编写一些单元测试但是我不知道怎么去关于创建IntPtr以传递给方法。我正在使用NUnit,不能使用模拟框架。
答案 0 :(得分:1)
查看Marshal.Copy()的各种重载,它们允许您使用IntPtr初始化值。
答案 1 :(得分:0)
如果我理解正确的话,你想在给定IntPtr的情况下对反序列化的逻辑进行单元测试 如果是这种情况,您所要做的就是拥有序列化输出的不同组合的副本以测试每个唯一路径。对于每个测试,获取IntPtr到可能的序列化实体,调用您的方法并验证预期结果。
获取指向内存区域的指针。将序列化输出保存在字符串中并从中获取Intptr。 GCHandle看起来像你需要的东西。 (从来没试过这个) http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.tointptr.aspx
答案 2 :(得分:0)
我对你的问题的解读让我觉得你所问的是:
如何创建模拟我正在进行的本机调用的函数,它将IntPtr返回到double或unicode字符串,以便我可以将IntPtr传递给我想要测试的函数?
这样的事情可能有所帮助:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
private static double myDouble = 3.14;
private static unsafe void TestPtrToDouble()
{
fixed(double* pDouble = &myDouble)
{
IntPtr intp = new IntPtr(pDouble);
double[] copy = new double[1];
Marshal.Copy(intp, copy, 0, 1);
Debug.Assert(copy[0] == myDouble);
}
}
private static char[] myString = { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' };
private static unsafe void TestPtrToUnicodeString()
{
fixed (char* pChar = &myString[0])
{
IntPtr intp = new IntPtr(pChar);
string copy = Marshal.PtrToStringUni(intp);
Debug.Assert(copy == "This is my string");
}
}
static void Main(string[] args)
{
TestPtrToUnicodeString();
TestPtrToDouble();
}
}
}
需要注意的是,您将无法返回从函数创建的模拟IntPtr。即,您无法创建P / Invoke调用的模拟版本,并希望工作正常。
.Net运行时在内存中移动托管对象(垃圾收集过程的一部分)。 fixed
语句会阻止您获取地址的成员/对象。但仅限于街区的生活。如果从函数返回,则块结束,因此返回后指针值可能无效。即,您的IntPtr可能正在引用不再包含您要编组的数据的内存。
查看unsafe code和fixed statement上的MSDN文档。但是我在这里得到的应该是正确的方向,为你的编组代码构建一个NUnit测试。
另请注意,此代码需要/ unsafe编译器选项进行编译。如果您需要在不支持不安全程序集的环境中运行程序集,则必须在另一个程序集中包含测试代码。但是既然你已经在使用P / Invoke,我想情况并非如此。