.Net单元测试之NMock
NMock是一款.NET平台下的基于动态代理的Mock模拟对象类库,用于C#开发。Mock对象使测试更简单,它测试单个组件或单个类时不需要其它所有组件真正实现。也就是说我们可以仅仅只是测试一个类,NMock生成的模拟是通过在运行时使用动态代理来实现的,这允许模拟对象动态的定义,并不需要添加任何附加的类。
通常,一个模拟的实现基于被依赖的接口而创建;NMock支持对接口和类的模拟,另外它还支持属性模拟。比起测试一个完整的对象关系树更容易查清楚Bug。Mock对象一般用于以测试为驱动的开发当中。
- 为什么需要Mock
- 什么情况下考虑使用Mock
- 进行Mock测试的步骤
- 测试代码首先引用NMock的框架
1) 定义一个接口来描述这个对象
2) 产品代码实现这个接口
3) 测试中Mock对象实现这个接口
下面是一个使用NMock的快速教程:
示例
现在我们来做一个简单的“Hello”例子,测试 Hello 类的 Greet() 方法,Hello 类依赖于一个 Person 对象,并将根据 Person 的名字向对应的账号发送祝贺(Greet)。这个例子很简单,其实用不到模拟对象,不过用来理解 NMock 是很合适的。public interface IPerson
{
string Name { get; }
}
然后定义具有 Greet 方法的 Hello 类,可以根据 IPerson 的名字发送祝贺信息。
public class Hello
{
IPerson person;
public Hello(IPerson person)
{
this.person = person;
}
public String Greet()
{
return "Hello " + person.Name;
}
}我们可以看到,Hello 类对 IPerson 接口有依赖。
在我们继续对 Hello 类的开发之前,让我们来学习一些关于 NMock 的基础知识。使用 NMock 很容易根据一个给定的接口或类来创建一个模拟对象;
1)首先你要实例化一个 Mock 对象,构建时要将你要模拟的接口或类的类型传递给 Mock 对象作为构建参数;
2)然后,你需要记录 Mock 对象的行为并最终通过 Mock 对象的属性来获得一个模拟类型的示例。下面是一个最简单的窗体的模拟对象,该模拟对象基于 IPerson 接口创建,没有记录任何行为。
//通知 NMock 你在模拟哪个接口或类
IMock mockPerson = new DynamicMock(typeof(IPerson));
//获取指定类型的一个模拟实例
IPerson person = (IPerson) mockPerson.MockInstance;
然而如果我们不记录模拟对象应该做些什么或者在它使用之前需要做一些什么处理,那么实际上这个模拟对象是毫无用处的;在下面的例子中,我们将记录并设置 IPerson 的 Name 属性的值。
NMock 有一个很长的很有用的 Expect 方法列表,使用这些列表我们可以设置模拟对象的行为,比如方法 A 被调用则返回 B,或者仅当用参数 C 调用方法 A 时才返回 B,或者当 A 方法被调用时则抛出异常 E,甚至我们可以告诉模拟对象它根本就不要指望能够调用方法 A。以上的简单例子表明我们希望 Name 属性只应该被调用一次,并且存取该属性时将返回字符串“John”;注意我们希望 Name 属性只应该被调用一次,我们可以通过调用模拟对象的 Verify() 方法来验证这一点。//通知 NMock 你在模拟哪个接口或类
IMock mockPerson = new DynamicMock(typeof(IPerson));//设置值
mockPerson.ExpectAndReturn("Name", "John");
//获取指定类型的一个模拟实例
IPerson person = (IPerson) mockPerson.MockInstance;
//在模拟对象上的预期检验
person.Verify();
这是一个简略的预期设置的方法列表:
Expect(string methodName, object[] args)
ExpectAndReturn(string methodName, object returnVal, object[] args)
ExpectAndThrow(string methodName, Exception exceptionVal, object[] args)
ExpectNoCall(string methodName)
现在设置好所有的基本条件,我们就可以简单的在对 Hello 类的测试中应用 NMock 了。
这就是我们的测试类:
[TestFixture]
public class HelloTest : Assertion
{
[Test]
public void TestExpect()
{
//模拟依赖
IMock person = new DynamicMock(typeof(IPerson));
//设置值
person.ExpectAndReturn("Name", "John");
Hello hello = new Hello((IPerson) person.MockInstance);
AssertEquals("Hello John", hello.Greet());
//检验 Name 属性是否只被调用了一次
person.Verify();
}
}