测试驱动 ASP.NET MVC(下)

利用 StructureMap 让依赖关系注入更上一层楼

StructureMap (structuremap.net) 是一种广泛采用的依赖关系注入框架。您可以使用程序包管理器控制台 (Install-Package StructureMap) 或 NuGet 程序包管理器 GUI(右键单击您的项目的引用文件夹,然后选择“管理 NuGet 程序包”)通过 NuGet 来安装该框架。
使用 StructureMap 配置依赖关系 在 ASP.NET MVC 中实现 StructureMap 的第一步是配置您的依赖关系,以便 StructureMap 知道如何对它们进行解析。您可以通过以下两种方法中的一种在 Global.asax 的 Application_Start 方法中配置依赖关系。
第一种方法是手动指示 StructureMap,对于特定的抽象实现,它应该使用特定的具体实现:

双击代码全选

1

2

3

4

ObjectFactory.Initialize(register=> {

register.For<ILoggingService>().Use<LoggingService>();

register.For<IEmployeeService>().Use<EmployeeService>();

});

 

此方法的缺点是您必须手动注册您的应用程序中的每个依赖关系,因此,对于大型应用程序而言,工作量可能会很大。此外,因为您在 ASP.NET MVC 站点的 Application_Start 中注册依赖关系,因此,您的 Web 层必须直接知道绑定有依赖关系的应用程序的其他每个层。
您还可以使用 StructureMap 自动注册和扫描功能自动检查您的程序集和绑定依赖关系。通过此方法,StructureMap 将扫描您的程序集,并且在它遇到某一接口时,会查找关联的具体实现(基于一个概念,即依据惯例,名为 IFoo 的方法将映射到具体实现 Foo):

双击代码全选

1

2

3

4

ObjectFactory.Initialize(registry => registry.Scan(x => {

x.AssembliesFromApplicationBaseDirectory();

x.WithDefaultConventions();

}));

 

StructureMap 依赖关系解决程序 在配置了您的依赖关系后,您需要能够从您的代码库访问这些依赖关系。这是通过创建依赖关系解决程序并将其定位于 Shared 项目中来实现的(因为它将需要由具有依赖关系的所有应用程序层来访问):

双击代码全选

1

2

3

4

5

publicstaticclassResolver {

publicstaticT GetConcreteInstanceOf<T>() {

returnObjectFactory.GetInstance<T>();

}

}

 

Resolver 类(我喜欢这么称呼它,因为 Microsoft 与 ASP.NET MVC 3 一起引入了 DependencyResolver 类,稍后我将讨论它)是包含一个函数的简单静态类。该函数接受泛型参数 T,该参数表示为其查找具体实现的接口;并且返回 T,这是传入接口的实际实现。
在我跳转到如何在您的代码中使用新的 Resolver 类之前,我想要介绍一下为什么我编写了自己开发的依赖关系解决程序,而不是创建实现随 ASP.NET MVC 3 引入的 IDependencyResolver 接口的类。包含 IDependencyResolver 功能是对 ASP.NET MVC 的很棒的补充,并且在促进正确的软件行为方面取得了很大的进步。但遗憾的是,它驻留在 System.Web.MVC DLL 中,而我不希望在应用程序体系结构的非 Web 层中具有对特定于 Web 技术的库的引用。
解析代码中的依赖关系 在完成了所有困难工作后,解析代码中的依赖关系就很简单了。您需要完成的全部工作就是调用 Resolver 类的静态 GetConcreteInstanceOf 函数,并且将其传递给您在为其查找具体实现的接口,如图 7 中所示。
图 7 解析代码中的依赖关系

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

publicclassEmployeeService : IEmployeeService {

privateILoggingService _loggingService;

publicEmployeeService() {

_loggingService = 

Resolver.GetConcreteInstanceOf<ILoggingService>();

}

publicdecimal CalculateSalary(longemployeeId) {

_loggingService.LogDebug(string.Format(

"Calculating Salary For Employee: {0}", employeeId));

decimal output = 0;

/*

* Complex logic that needs to be performed

* in order to determine the employee's salary

*/

returnoutput;

}

}

 

利用 StructureMap 在单元测试中注入 Test Double 现在已完成了代码的结构设计,因此,您可以注入依赖关系而无需来自使用者的介入,让我们回到在单元测试中正确处理依赖关系这个最初的任务中来吧。它的具体情形是这样的:
该任务是使用 TDD 撰写逻辑,以便生成要从 EmployeeService 的 CalculateSalary 方法返回的薪金值。(您将会在图 7 中发现 EmployeeService 和 CalculateSalary 函数。)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Grow your business fast with

Suku