再进一步思考,我们会给出一个自然的解决方案,把考区类,考试定义类抽象出两个接口来,构造器传入接口定义,而不是类本身。这其实是对层与层之间依赖注入的一个模仿。但是,相信我,这个方向是另一个梦魇的入口。业务域和多层之间完全是不同的环境。不想太深入讨论,可能独立一篇文章都打不住。

  幸好,我们有另一个工具Rhino Mock,能帮助我们解决类的模拟的问题。改造之后的测试代码如下。的影响是,你需要为被模拟的类,加入一个至少是protected的无参数构造器。这其实不是个大问题,如果你同时在项目中使用nHibernate的话,也会有类似的要求。

  看代码:

public class When_create_an_exam
    {
        private Establish context =
            () =>
                {
                    stub_exam_def = MockRepository.GenerateMock<ExamDef>();
                    stub_district = MockRepository.GenerateMock<District>();
                    stub_date = MockRepository.GenerateMock<Date>();
                };
    //...此处省略的没有修改的代码
    }

  可以看到,这一次的重构,把考试代码、考区代码等,其实你根本不关心的信息已经省略掉了。

  AutoMocking --- 懒的高境界

  到这还不够,后一个问题是填饱我们肚子的有一块烧饼。

  隆重介绍AutoMocking,自动模拟。当你的测试类从AutoMock的Specification类继承时,它会自动为你创建一个被测试对象subject,并且根据被测试对象构建器的参数定义,全自动的创建模拟对象。而引用这些模拟对象的方式,

  很简单Dependency<ExamDef>,是依赖注入的依赖这个词。已经不需要太多的解释---名如其实。

  再看代码:

public class When_create_an_exam:Specification<Exam>
    {
        private It should_assign_to_properties =
            () =>
                {
                    subject.District.ShouldEqual(DependencyOf<District>());
                    subject.ExamDef.ShouldEqual(DependencyOf<ExamDef>());
                    subject.Date.ShouldEqual(DependencyOf<Date>());
                };
    }

  三行实现代码,对应三行测试代码。简洁的不能再简洁了。