在做单元测试的过程中,需要灵活地运用这三种Test Fixture的准备方法。例如在我的工作当中,我在以下情况使用到了隐式准备方式:

在某一个测试项目中,由于测试的数据不多,所以我使用了XmlSerializer,把测试的数据都放在一个XML文件中,然后利用 XmlSerializer把XML中的数据映射到相应的配置类中。对于这样的情况,这些测试数据在测试运行的全过程中都需要用到,所以我选择了在测试类初始化的时候,只运行1次,来准备这些测试数据(Test Fixture的一部分)。

1 [ClassInitialize()]

2 public static void MyClassInitialize(TestContext testContext)

3 {

4 XmlSerializer xmlSerializer = new XmlSerializer(typeof(Config));

5 FileStream fs = new FileStream("Config.xml", FileMode.Open);

6 config = (Config)xmlSerializer.Deserialize(fs);

7 }

还是在同一个项目中,我想让每一个测试之间互相不要受到影响,所以我在[TestInitialize()]方法中对于一个Web Service的客户端进行初始化,保证每一次运行测试前,这个客户端都是“新”的

1 [TestInitialize()]

2 public void MyTestInitialize()

3 {

4 USi18nService = new InteropWebSerivce();

5 USi18nService.Url = config.USi18nAddress;

6 }

在另外的一个项目中,需要对一个方法进行测试,该方法的功能是根据Email地址从PreSignup表里面获取相关的资料,那么首先要做的是完成一个PreSignup的操作,才能检查这个方法。而完成PreSignup操作并不是所有的测试都需要的,所以我不选择隐式调用,而是选择委托调用,调用一个外部的帮助方法,来帮助我完成PreSignup操作;同时这个PreSignup的操作在其他一些测试中也是需要的,所以也达到了重用的效果。

那么在什么时候会用到内联方法来准备Test Fixture呢?其实我自己经常用这种方法,有以下一个场景,我需要对一个方法进行测试,这个方法要做的事情是检查一个电话号码是否符合规范,那么我会先创建一个List,然后在List里面填充了各种不同的电话号码,然后在后面用一个foreach语句把List里面的数据遍历一遍,可能这些电话号码的数据只在这一个方法里面才有用,所以我没有选择把它抽取成一个方法。

其实不同的单元测试框架有不同的思想,例如在NUnit里面,一个测试类的标签是叫[Test Fixture],其实作者的设计思想是一个测试类,是一套Test Fixture;如果不是一套Test Fixture,那么不要把测试方法写到一起。其实这三种方法各有所长,在我刚开始学习和尝试做单元测试的时候,我刚接触到类似[Setup] [TearDown]这样的隐式调用的时候,我觉得这是银弹,我要充分使用它。但是随着工作的深入,发现这个隐式调用会带来一些问题,然后慢慢转用了调外部方法,或者直接内联到测试方法中。只有结合实际情况,结合的上下文来运用这些方法,才能真正提高单元测试代码的质量,减少我们的工作量。