MOQ TIP1:简介加基础

简介: MOQ来自于http://code.google.com/p/moq/。下载后其实是直接作为DLL被引用的。 Mock是模拟对象的一种技术。 它可以用于以下情况: ----- 真实对象具有不可确定的行为(产生不可预测的结果,如股票的行情) ----- 真实对象很难被创建(比如具体的web容器...

MOQ来自于http://code.google.com/p/moq/。下载后其实是直接作为DLL被引用的。

Mock是模拟对象的一种技术。

它可以用于以下情况:

----- 真实对象具有不可确定的行为(产生不可预测的结果,如股票的行情)

----- 真实对象很难被创建(比如具体的web容器)

----- 真实对象的某些行为很难触发(比如网络错误)

----- 真实情况令程序的运行速度很慢

----- 真实对象有用户界面

----- 测试需要询问真实对象它是如何被调用的(比如测试可能需要验证某个回调函数是否被调用了)

----- 真实对象实际上并不存在(当需要和其他开发小组,或者新的硬件系统打交道的时候,这是一个普遍的问题)

1:测试返回值

需要被测试的代码:

    public interface ICounter
    {
        int CountArgs(int a, int b);
    }

    public class SampleClass
    {
        private ICounter _counter;
        public SampleClass(ICounter counter)
        {
            _counter = counter;
        }

        public int GetResoult()
        {
            return _counter.CountArgs(1, 2) + 3;
        }
    }

测试代码:

            Mock<ICounter> mock = new Mock<ICounter>();
            mock.Setup(counter => counter.CountArgs(1, 2)).Returns(3);
            SampleClass sample = new SampleClass(mock.Object);
            int re = sample.GetResoult();
            mock.Verify();
            Assert.AreEqual(re, 6);

2:测试抛出异常

假设待测试代码为:

    public interface ICounter
    {
        int CountArgs(int a, int b);
    }

    public class SampleClass
    {
        private ICounter _counter;
        public SampleClass(ICounter counter)
        {
            _counter = counter;
        }

        public int GetResoult()
        {
            return _counter.CountArgs(100, 123) + 3;
        }
    }

测试代码则为:

            Mock<ICounter> mock = new Mock<ICounter>();
            mock.Setup(arg => arg.CountArgs(100, 123)).Throws(new ArgumentException("参数过大"));
            SampleClass sample = new SampleClass(mock.Object);
            try
            {
                int re = sample.GetResoult();
                mock.Verify();
            }
            catch (ArgumentException)
            {
                return;
            }
            Assert.Inconclusive("error");

3:一些限制

MOQ可以直接模拟接口,但是在模拟类的时候,有如下限制:

类不能是密封的;

方法要加上虚修饰符;

不能模拟静态方法(可以通过适配器模式来模拟静态方法);

其实这些限制中,一般来说我们是不需要模拟类的,但是抽象类还是需要模拟的比较多,比如:

    public abstract class CounterBase
    {
        public abstract int CountArgs(int a, int b);

        public int ArgProp { get; set; }

        public virtual string GetSomethingVitual()
        {
            return ArgProp.ToString();
        }

        public string GetSomethingReal()
        {
            return "abc";
        }

    }

    public class SampleClass
    {
        private CounterBase _counter;
        public SampleClass(CounterBase counter)
        {
            _counter = counter;
        }

        public int GetResult()
        {
            return _counter.CountArgs(1, 2) + 3;
        }

        public string GetVitual()
        {
            return _counter.GetSomethingVitual();
        }

        public string GetReal()
        {
            return _counter.GetSomethingReal();
        }
    }

在这里,作为调用者SampleClass来说,由于使用到了CounterBase,所以CounterBase 这个抽象类就是有必要被模拟的。SampleClass演示了调用抽象方法、虚方法、普通方法,运行的结果是:

------ Test started: Assembly: TestProject1.dll ------

Test 'TestProject1.ProgramTest.TestReal' failed: Test method TestProject1.ProgramTest.TestReal threw exception: 
System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: arg => arg.GetSomethingReal()
	at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo method)
	at Moq.Mock.<>c__DisplayClass1c`2.<Setup>b__1b()
	at Moq.PexProtector.Invoke[T](Func`1 function)
	at Moq.Mock.Setup[T,TResult](Mock mock, Expression`1 expression, Func`1 condition)
	at Moq.Mock`1.Setup[TResult](Expression`1 expression)
	ProgramTest.cs(101,0): at TestProject1.ProgramTest.TestReal()

2 passed, 1 failed, 0 skipped, took 1.32 seconds (MSTest 10.0).

我们可以看到,前面两个方法都成功,只有那个非虚拟的普通方法失败,信息如下:

Invalid setup on a non-virtual (overridable in VB) member: arg => arg.GetSomethingReal()

image

本篇代码下载:ConsoleApplication20110812.rar

Creative Commons License本文基于 Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 http://www.cnblogs.com/luminji(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。
目录
相关文章
|
数据安全/隐私保护 C++ iOS开发
软件开发入门教程网 Search之C++ 继承
软件开发入门教程网 Search之C++ 继承
|
3月前
|
API Java 开发框架
【从零到精通】如何用Play Framework快速构建RESTful API?看完这篇你就懂了!
【8月更文挑战第31天】《Play Framework快速入门:从零开始构建RESTful API》介绍了如何使用高性能Web开发框架Play Framework构建简单的RESTful API。从环境搭建到项目创建,再到实现用户列表的增删查功能,本文档详细指导每个步骤,并解释核心概念。适合初学者快速上手。首先确保已安装JDK和sbt,然后通过sbt创建Play项目,接着定义控制器、模型及路由,最后运行应用进行测试。通过本教程,你将掌握构建RESTful API的基础知识,为进一步学习Play Framework打下坚实基础。
47 0
|
6月前
|
JSON 安全 数据安全/隐私保护
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
97 0
|
6月前
|
JSON 安全 数据安全/隐私保护
iOS Class Guard github用法、工作原理和安装详解及使用经验总结
iOS Class Guard github用法、工作原理和安装详解及使用经验总结
80 0
|
编译器 C语言 C++
软件开发入门教程网 Search之C++ 类 & 对象
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。
|
前端开发 JavaScript
前端框架:第二章:Layui(类UI ) 框架:关于2.2.5版本没有rate模块的解决方案
前端框架:第二章:Layui(类UI ) 框架:关于2.2.5版本没有rate模块的解决方案
218 0
前端框架:第二章:Layui(类UI ) 框架:关于2.2.5版本没有rate模块的解决方案
|
JavaScript
WebApi入门第五章(attribute语法学习 )
WebApi入门第五章(attribute语法学习 )
110 0
WebApi入门第五章(attribute语法学习 )
|
JavaScript 前端开发 Java
|
前端开发
前端学习案例-手把手教你封装一个ant design的审核框组件
前端学习案例-手把手教你封装一个ant design的审核框组件
167 0