C# 如何模拟DLL导入

C# 如何模拟DLL导入,c#,unit-testing,moq,dllimport,extern,C#,Unit Testing,Moq,Dllimport,Extern,我正在尝试编写一个类的单元测试用例,该类使用Dll导入,如下所示 [DllImport("user32.dll")] public static extern IntPtr FindWindow(string name, string windowName); 为了测试这个类,我想用MOQ模拟上面的语句,但是我不知道如何为它设置模拟 我还想知道上述是否可以实现。如果不能,那么需要做什么才能使其可测试 我知道要使这个类可测试,我们需要在这些语句上创建包装器,并且需要在一个单独的类中将其分离出

我正在尝试编写一个类的单元测试用例,该类使用Dll导入,如下所示

 [DllImport("user32.dll")]
 public static extern IntPtr FindWindow(string name, string windowName);
为了测试这个类,我想用MOQ模拟上面的语句,但是我不知道如何为它设置模拟

我还想知道上述是否可以实现。如果不能,那么需要做什么才能使其可测试

我知道要使这个类可测试,我们需要在这些语句上创建包装器,并且需要在一个单独的类中将其分离出来


想知道有没有其他方法可以达到同样的效果。

您不能模拟静态方法,只能模拟具有虚拟成员的接口或类。但是,您可以将该方法包装为虚拟方法,您可以包装:

interface StaticWrapper
{
    InPtr WrapStaticMethod(string name, string windowName);
}
class MyUsualBehaviour : IStaticWrapper
{
    public InPtr WrapStatic(string name, string windowName)
    {
        // here we do the static call from extern DLL
        return FindWindow(name, widnowName);
    }
}
但是,现在可以模拟该接口而不是静态方法:

var mock = new Moq<IStaticWrapper>();
mock.Setup(x => x.WrapStatic("name", "windowName")).Returns(whatever);
var mock=new Moq();
mock.Setup(x=>x.WrapStatic(“name”,“windowName”))。返回(无论什么);
此外,您在代码中调用的不是extern方法,而是减少代码与特定库耦合的包装器


请参阅此链接以了解进一步的解释:您不能模拟静态方法,而只能模拟具有虚拟成员的接口或类。但是,您可以将该方法包装为虚拟方法,您可以包装:

interface StaticWrapper
{
    InPtr WrapStaticMethod(string name, string windowName);
}
class MyUsualBehaviour : IStaticWrapper
{
    public InPtr WrapStatic(string name, string windowName)
    {
        // here we do the static call from extern DLL
        return FindWindow(name, widnowName);
    }
}
但是,现在可以模拟该接口而不是静态方法:

var mock = new Moq<IStaticWrapper>();
mock.Setup(x => x.WrapStatic("name", "windowName")).Returns(whatever);
var mock=new Moq();
mock.Setup(x=>x.WrapStatic(“name”,“windowName”))。返回(无论什么);
此外,您在代码中调用的不是extern方法,而是减少代码与特定库耦合的包装器


请参阅此链接以了解进一步的解释:实际上,您可以使用typemock隔离器模拟导出DLL中的方法,而无需对代码进行任何不必要的更改。 您只需要导出Dll并将该方法模拟为任何其他静态方法, 例如:

public class ClassUnderTest
    {

        public bool foo()
        {
            if(Dependecy.FindWindow("bla","bla") == null)
            {
                throw new Exception();
            }
            return true;
        }
    }

public class Dependecy
{//imported method from dll
     [DllImport("user32.dll")]
     public static extern IntPtr FindWindow(string name, string windowName);
 }

        [TestMethod]
        public void TestMethod1()
        {
            //setting a mocked behavior for when the method will be called
            Isolate.WhenCalled(() => Dependecy.FindWindow("", "")).WillReturn(new IntPtr(5));

            ClassUnderTest classUnderTest = new ClassUnderTest();
            var res = classUnderTest.foo();

            Assert.IsTrue(res);
        }

您可以看到有关Pinvoked方法的更多信息

实际上,您可以使用typemock隔离器模拟导出DLL中的方法,而无需对代码进行任何不必要的更改。 您只需要导出Dll并将该方法模拟为任何其他静态方法, 例如:

public class ClassUnderTest
    {

        public bool foo()
        {
            if(Dependecy.FindWindow("bla","bla") == null)
            {
                throw new Exception();
            }
            return true;
        }
    }

public class Dependecy
{//imported method from dll
     [DllImport("user32.dll")]
     public static extern IntPtr FindWindow(string name, string windowName);
 }

        [TestMethod]
        public void TestMethod1()
        {
            //setting a mocked behavior for when the method will be called
            Isolate.WhenCalled(() => Dependecy.FindWindow("", "")).WillReturn(new IntPtr(5));

            ClassUnderTest classUnderTest = new ClassUnderTest();
            var res = classUnderTest.foo();

            Assert.IsTrue(res);
        }


您可以查看有关Pinvoked方法的更多信息

,但必须确保使用DLL导入static,但是你可以简单地将对该静态方法的调用隐藏到对另一个方法的调用中。是的。但是当我尝试为该包装类编写单元测试时,我将处于相同的情况。我知道我们需要划定一条线,以确定可以编写哪一级别的单元测试用例。DllImport是一个声明,而不是一个方法。等效项是程序集引用。无论如何,将所有DllImport声明放在一个类中是一种很好的做法。但是使用DLL import static必须确保,但是你可以简单地将对该静态方法的调用隐藏到对另一个方法的调用中。是的。但是当我尝试为该包装类编写单元测试时,我将处于相同的情况。我知道我们需要划定一条线,以确定可以编写哪一级别的单元测试用例。DllImport是一个声明,而不是一个方法。等效项是程序集引用。无论如何,将所有DllImport声明放在一个类中是一种很好的做法。@RishiTiwari为什么不这样做呢?您所问的问题相当于“如何模拟程序集引用”?DllImport不是一个要模拟的方法,它是一个声明——对库中特定入口点的引用。实际上,在单个类中收集DllImport声明是一种很好的做法。我只是想知道是否可以模拟DLL导入…为了使其可测试,我知道需要一个包装器,谢谢anyways@RishiTiwari正如我已经提到的,由于上述原因,这是不可能的。对程序集的引用在项目中是静态的。你不能简单地说:只在那个时候引用那个程序集,但为了测试,我想忘记那个。在你的语句中用
程序集引用
替换
dll导入
。这有意义吗?如何模拟程序集引用?如果不这样做,您应该使用一个公共接口和一个实现它的mock。因此wrapper@RishiTiwari那你为什么不做呢?您所问的问题相当于“如何模拟程序集引用”?DllImport不是一个要模拟的方法,它是一个声明——对库中特定入口点的引用。实际上,在单个类中收集DllImport声明是一种很好的做法。我只是想知道是否可以模拟DLL导入…为了使其可测试,我知道需要一个包装器,谢谢anyways@RishiTiwari正如我已经提到的,由于上述原因,这是不可能的。对程序集的引用在项目中是静态的。你不能简单地说:只在那个时候引用那个程序集,但为了测试,我想忘记那个。在你的语句中用
程序集引用
替换
dll导入
。这有意义吗?如何模拟程序集引用?如果不这样做,您应该使用一个公共接口和一个实现它的mock。因此,,Wrapper我想使用MOQ做同样的事情。我们使用MOQ框架来模拟我们的依赖项…不能使用任何其他框架…但感谢您展示,如果我们使用类型模拟,我们实际上也可以模拟DLL导入调用。我投票支持您的答案,但不能将其标记为答案。我想使用MOQ做同样的事情。我们使用MOQ框架来模拟我们的依赖项…无法使用任何其他框架…但感谢您展示,如果我们使用类型模拟,我们实际上也可以模拟DLL导入调用。对您的答案进行了投票,但无法将其标记为答案。