MOQ TIP1:简介加基础
MOQ来自于http://code.google.com/p/moq/。下载后其实是直接作为DLL被引用的。
Mock是模拟对象的一种技术。
它可以用于以下情况:
----- 真实对象具有不可确定的行为(产生不可预测的结果,如股票的行情)
----- 真实对象很难被创建(比如具体的web容器)
----- 真实对象的某些行为很难触发(比如网络错误)
----- 真实情况令程序的运行速度很慢
----- 真实对象有用户界面
----- 测试需要询问真实对象它是如何被调用的(比如测试可能需要验证某个回调函数是否被调用了)
----- 真实对象实际上并不存在(当需要和其他开发小组,或者新的硬件系统打交道的时候,这是一个普遍的问题)
1:测试返回值
需要被测试的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } } |
测试代码:
1 2 3 4 5 6 | 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:测试抛出异常
假设待测试代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } } |
测试代码则为:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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可以直接模拟接口,但是在模拟类的时候,有如下限制:
类不能是密封的;
方法要加上虚修饰符;
不能模拟静态方法(可以通过适配器模式来模拟静态方法);
其实这些限制中,一般来说我们是不需要模拟类的,但是抽象类还是需要模拟的比较多,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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演示了调用抽象方法、虚方法、普通方法,运行的结果是:
1 2 3 4 5 6 7 8 9 10 11 12 | ------ 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()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器