【问题标题】:How to mock a DLL Import如何模拟 DLL 导入
【发布时间】:2016-11-30 10:01:03
【问题描述】:

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

 [DllImport("user32.dll")]
 public static extern IntPtr FindWindow(string name, string windowName);

为了测试课程,我想使用 MOQ 模拟上述语句,但无法弄清楚如何为其设置模拟。

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

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

想知道是否有任何其他选择可以达到同样的效果。

【问题讨论】:

  • 但必须使用 DLL 导入静态
  • 当然可以,但是您可以简单地将对该静态方法的调用隐藏到对另一个方法的调用中。
  • 是的..但是当我尝试为该包装类编写单元测试时,我会遇到同样的情况
  • 我知道我们需要画一条线来表示可以编写单元测试用例的最高级别..
  • DllImport 是一个声明,而不是一个方法。等效项是程序集引用。无论如何,最好将所有 DllImport 声明放在一个类中。

标签: c# unit-testing moq dllimport extern


【解决方案1】:

实际上,您可以使用 typemock Isolator 从导出的 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 Methods here

【讨论】:

  • 我想用最小起订量做同样的事情。我们正在使用最小起订量框架来模拟我们的依赖关系......不能使用任何其他框架......但是感谢您展示如果我们使用类型模拟我们可以实际上也模拟了 DLL 导入调用。对您的答案投了赞成票,但不能将其标记为答案。
【解决方案2】:

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

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);

此外,您不会在代码中调用 extern 方法,而只是调用减少与特定库的代码耦合的包装器。

查看此链接以获得进一步的解释:http://adventuresdotnet.blogspot.de/2011/03/mocking-static-methods-for-unit-testing.html

【讨论】:

  • @RishiTiwari 那你为什么不这样做呢?你问的是“我如何模拟程序集引用”的等价物? DllImport 不是一种模拟方法,它是一个 声明 - 对库中特定入口点的引用。在单个类中收集 DllImport 声明实际上是一种好习惯。
  • 我只是想知道是否可以模拟 DLL 导入...使其可测试我知道需要一个包装器,无论如何谢谢
  • @RishiTiwari 正如我已经提到的,由于上述原因,这是不可能的。对程序集的引用在您的项目中是静态的。你不能简单地说:只是偶尔引用那个程序集,但是为了测试我想忘记这一点。
  • 在您的声明中将dll import 替换为assembly reference。是否有意义?您将如何模拟程序集引用?你不会,你会使用一个通用接口和一个实现它的模拟。因此,包装器
猜你喜欢
  • 2019-01-20
  • 2020-09-30
  • 2016-05-16
  • 2015-12-14
  • 1970-01-01
  • 2019-05-17
  • 1970-01-01
  • 2020-05-27
  • 2020-11-29
相关资源
最近更新 更多