0

我正在使用一个本机库,它将 IntPtr 返回到包含属性值的内存位置。我知道属性的类型是什么,并且我有一种方法可以从指针指向的内存中编组一个值(获取 IntPtr 和属性的类型)。此方法调用 Marshal.ReadInt32,或读取一系列字节并将它们转换为双精度,或使用 Marshal.PtrToStringUni 等读取字符串。我想为此方法编写一些单元测试,但不确定我该怎么做关于创建 IntPtr 以传递给该方法。我正在使用 NUnit,不能使用模拟框架。

4

3 回答 3

1

查看Marshal.Copy()的各种重载,这将允许您使用 IntPtr 初始化值。

于 2008-10-22T09:53:32.930 回答
0

如果我理解正确,你想对你的反序列化逻辑进行单元测试,给定一个 IntPtr。
如果是这种情况,您所要做的就是拥有序列化输出的不同组合的副本,以测试每个唯一路径。对于每个测试,获取可能的序列化实体的 IntPtr,调用您的方法并验证预期结果。

类似于获取指向内存区域的指针。将序列化的输出保存在一个字符串中,并从中获取一个 Intptr。GCHandle 看起来像你需要的东西。(虽然从未尝试过) http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.tointptr.aspx

于 2008-10-22T09:49:34.277 回答
0

我对您的问题的阅读使我认为您要问的是:

如何创建模拟我正在进行的本机调用的函数,该调用将 IntPtr 返回到双精度或 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 可能正在引用不再包含您要编组的数据的内存。

查看有关不安全代码固定语句的 MSDN 文档。但是我在这里得到的内容应该会让您朝着正确的方向前进,为您的编组代码构建 NUnit 测试。

另请注意,此代码需要 /unsafe 编译器选项才能编译。如果您需要您的程序集在不支持不安全程序集的环境中运行,您必须在另一个程序集中拥有测试代码。但是由于您已经在使用 P/Invoke,我想情况并非如此。

于 2008-10-22T10:44:12.857 回答