【IT168 技术文章】
一、Mono简介
Mono是由Novell公司(著名的Suse Linux就是其产品)开发的一款开源的.net程序运行平台。长期以来,.net因为有微软这棵大树,还是颇受推崇的,包括我个人也很推崇。不过由于不具备跨操作系统平台的能力,比如说将程序由Windows移植到Linux上,因此也颇遭诟病。Mono所应对的正是这一情况。
Mono不仅提供了基本的.net类库,也有自己的扩展。但Mono现在还不太完善,更多的时候只能用于技术尝试,不过毕竟实现了.net程序跨平台。现在Mono最新版本是1.1.13.2,可以从http://www.mono-project.com/Downloads上下载,本文使用的是1.1.12.1(安装到了本机的C:\Program Files\Mono-1.1.12.1文件夹下,但没有安装.net环境)。Mono提供了包括C#(mcs)和VB.net(mbas)等在内的多款编译器,还提供了一个XSP服务器,能够运行ASP.net程序了。但这里将只会用到C#。
二、NUnit简介
NUnit是一款堪与JUnit齐名的开源的回归测试框架,供.net开发人员做单元测试之用,可以从http://www.nunit.org/网站上免费获得。本文使用的是Mono自带的NUnit 2.2.0。
三、编写用于测试的类
用于测试的类很简单,名为Book,只有id和name两个属性,这两个属性将分别用于两个用例当中。由于我没有在当前的系统中安装.net环境,自然也无法使用Visual Studio.net、Delphi或是SharpDevelop这些开发工具,只好用记事本了。
打开记事本后,首先将该文件保存,我保存在了本机的G:\MDZPCK\Mono\NUnit文件夹下,文件名Book.cs。然后输入代码,如下:
using System;
namespace NUnitCS
{
public class Book
{
private string pid = null;
private string pname = null;
public string id
{
get
{
return pid;
}
set
{
pid = value;
}
}
public string name
{
get
{
return pname;
}
set
{
pname = value;
}
}
}
}
至此,用于测试的类编写完成了。
四、编写测试用例
这里只用了一个类进行测试,名为BookTest,以前这样的类可能需要继承NUnit.Framework.TestCase类,但现在只需要对该类使用TestFixture属性进行标识即可,而无须继承了。BookTest类包含两个用例,分别对应该类的testId和testName方法,即每个方法实现了一个测试用例。注意,在NUnit中,这些用来实现测试用例的方法有两种手段进行标识:一个是以testXXX的格式来命名,一个是使用Test属性进行标识。此外,BookTest还有Init和Dispose这两个方法,并分别使用TestFixtureSetUp和TestFixtureTearDown属性来进行标识,前者在每个测试方法开始之前执行,多用来做初始化;后者在每个测试方法完成之后执行,多用来清理资源。注意,这两个方法的名称并没有什么限制,但必须用TestFixtureSetUp和TestFixtureTearDown属性进行标识。下面开始编写BookTest。
在记事本中新建文件,与Book.cs保存在同一目录下,文件名BookTest.cs。然后输入代码,如下:
using System;
using NUnit.Framework;
namespace NUnitCS
{
[TestFixture]
public class BookTest
{
Book book = null;
[TestFixtureSetUp]
public void Init()
{
Console.WriteLine("测试开始!");
book = new Book();
Console.WriteLine("book对象被初始化!");
}
[Test]
public void testId()
{
book.id = "001"; //设置id属性的值为001
//使用Assert查看id属性的值是否为001
Assert.AreEqual("001", book.id);
Console.WriteLine("id属性被测试!");
}
[Test]
public void testName()
{
book.name = "ASP"; //设置name属性的值为ASP
//使用Assert查看name属性的值是否为JSP,这是个必然出现错误的测试
Assert.AreEqual("JSP", book.name);
Console.WriteLine("name属性被测试!");
}
[TestFixtureTearDown]
public void Dispose()
{
Console.WriteLine("book对象将被清理!");
book = null;
Console.WriteLine("测试结束!");
}
}
}
这里Init和Dispose方法没什么好说的,就是执行了对book对象的初始化和清理,不过testId和testName需要说明一下。前者是在对book的id属性进行测试,首先赋值为”001”,然后使用Assert的AreEqual方法查看id属性中存放的值是否是期待的值,由于我的期待值也是”001”,所以执行后这个用例应该是成功的;后者则是对book的name属性进行测试,也是首先赋值为”ASP”,然后使用Assert的AreEqual方法查看其值是否是期待的,由于我特意将期待值设定为根本不可能的”JSP”,因此这个用例执行后会出现一个错误。但请注意,由于我是特意要让测试出现错误,所以将期待值设定成了不可能的值,如果你是测试人员,请千万不要这么做,否则如果别的地方导致了错误,很容易给自己造成不必要的麻烦。
下面简单介绍一下上边用到的静态类NUnit.Framework.Assert。该类主要包含7个方法:
1.AreEqual()方法,用来查看对象中存的值是否是期待的值,与字符串比较中使用的Equals()方法类似;
2.IsFalse()和IsTrue()方法,用来查看变量是是否为false或true,如果IsFalse()查看的变量的值是false则测试成功,如果是true则失败,IsTrue()与之相反;
3.AreSame()方法,用来比较两个对象的引用是否相等,类似于通过“Is”或“==”比较两个对象;
4.IsNull()和IsNotNull()方法,用来查看对象是否为空和不为空;
5.Fail()方法,意为失败,用来抛出错误。我个人认为有两个用途:首先是在测试驱动开发中,由于测试用例都是在被测试的类之前编写,而写成时又不清楚其正确与否,此时就可以使用Fail方法抛出错误进行模拟;其次是抛出意外的错误,比如要测试的内容是从数据库中读取的数据是否正确,而导致错误的原因却是数据库连接失败。
下面,还需要用记事本再编写一个文件,该文件中将包含main函数,以做为程序的入口点,我将该文件保存为Class1.cs。代码如下:
using System;
namespace NUnitCS
{
class Class1
{
static void Main(string[] args) {}
}
}
至此,编码完成。
下面用Mono提供的mcs来编译程序。不过在编译之前,请确认Mono安装目录(我的安装目录是C:\Program Files\Mono-1.1.12.1)下的bin文件夹是否被配置到了环境变量path中。虽然这不是必须的,但编译程序时会方便一点。配置好后,打开命令行工具,将路径定位到保存源码文件的文件夹下,然后运行如下命令:
mcs –r:nunit.framework.dll –out:NUnit.exe Class1.cs Book.cs BookTest.cs
如下图所示:
这里第一行命令对环境变量path做了临时配置,以防有人不会配置。不过这么做只是临时的,关掉命令行窗口后该配置就会遗失,但也没办法,要是通过“我的电脑”来配置,演示起来太麻烦了。下面简单介绍一下这里所执行mcs命令:
1. 参数-r,用来调用动态连接库。这里调用的nunit.framework.dll就是Mono自带的NUnit类库。
2.参数-out,要输出的文件的名字,需要加扩展名。
执行后,在保存源码的文件夹下生成一个名为NUnit.exe的可执行文件。
五、运行NUnit
编码完成后,就可以使用NUnit进行测试了。Mono自带的NUnit只提供了控制台工具,执行命令如下:
nunit-console NUnit.exe
执行结果如下:
执行结束后,目录下会生成一个TestResult.xml文件,该文件以XML格式保存了测试结果信息。
六、小结
与半年前相比,Mono已经有了很大进步,至少对中文的支持就比以前强多了,而且现在学习Mono的人也越来越多,资料也相对容易获得,不过与Sun的Java、MS的.net相比还是有些弱小。但任何事物也不是一蹴而就的,Java能有今天也要走过十年,而.net则更是由于有了微软这棵大树,因此对于Mono,我有着更多的期待。