代码之家  ›  专栏  ›  技术社区  ›  Nathan W

模拟COM对象

  •  2
  • Nathan W  · 技术社区  · 16 年前

    我一直在研究一个只能接受和返回字符串的COM对象的包装器。COM对象的接口如下:

        interface IMapinfo
        {
            void Do(string cmd);
            string Eval(string cmd);
        }
    

    现在,我已经创建了这样的类来封装基本函数:

        public class Table 
        {
            IMapinfo MI;
            public string Name
            {
                //pass the command to the COM object and get back the name.
                get{return MI.Eval("TableInfo(1,1")");}
            }
    
        }
    

    现在,我想对这些类进行单元测试,而不必每次都创建真正的COM对象,设置世界然后运行测试。所以我一直在研究使用mock对象,但我对在这种情况下如何使用mock有点困惑。

    我打算使用Moq,所以我写了这样的测试:

            [Test]
            public void MockMapinfo()
            {
                Moq.Mock<Table> MockTable = new Moq.Mock<Table>();
                MockTable.ExpectGet(n => n.Name)
                    .Returns("Water_Mains");
    
                Table table = MockTable.Object;
                var tablename = table.Name;
    
                Assert.AreEqual("Water_Mains", tablename,string.Format("tablename is {0}",tablename));
                Table d = new Table();
             }
    

    这是模拟COM对象的正确方法吗?如何验证发送到eval函数的字符串是正确的?还是我做错了?

    1 回复  |  直到 16 年前
        1
  •  3
  •   Community CDub    8 年前

    这是复制品吗? How would I do TDD with a COM OLE object

    编辑:看起来你在问同样的问题,但是为了验证你的模拟代码(OOPS)。

    你并不完全适合你的模拟场景。你想隔离外部依赖是对的,你的COM对象当然符合这个标准。虽然我不是一个moq人(我更喜欢RhinoMocks),但模拟背后的想法是 交互测试。..

    交互测试是关于有凝聚力的对象集如何协同工作的。在这种情况下,一个有效的测试是为依赖于COM对象行为的组件编写一个测试。

    在这种情况下,充当COM对象包装器的“表”也取决于COM对象的行为。为了便于讨论,假设Table对象对COM对象返回的值执行自定义逻辑。

    现在,您可以为Table对象编写隔离测试,同时 模拟 COM对象的行为使用Mocks。

    public class Table
    {
       public Table(IMapInfo map)
       {
          _map = map;
       }
    
       public string Name
       {
          get 
          {
            string value = _map.Eval("myexpression");
            if (String.IsNullOrEmpty(value))
            {
                value = "none";
            }
            return value;
          }
       }
    
       private IMapInfo _map;
    }
    
    [TestFixture]
    public class TableFixture // is this a pun?
    {
       [Test]
       public void CanHandleNullsFromCOM()
       {
           MockRepository mocks = new MockRepository(); // rhino mocks, btw
           IMapInfo map = mocks.CreateMock<IMapInfo>();
    
           using (mocks.Record())
           {
              Expect.Call(map.Eval("myexpression").Return(null);
           }
    
           using (mocks.PlayBack())
           {
              Table table = new Table(map);
              Assert.AreEqual("none", table.Name, "We didn't handle nulls correctly.");
           }
    
           mocks.verify();
       }
    }
    

    也许COM对象在调用时会抛出异常,或者它不能很好地处理字符串表达式。我们实际上是在测试Table对象如何与IMapInfo交互,而不与COM对象的实现绑定。我们还强制表和IMapInfo之间的关系,因为必须在测试期间调用IMapInfo对象。

    希望这能有所帮助。