0

我有一个带有标准 IoC 设置的 MVC 项目,它使用 StructureMap 将存储库注入控制器构造函数。

我还决定我想要一个静态“实用程序”类,我可以在其中拥有可由不同控制器调用的通用方法。例如,我有:

public static IEnumerable<CountryCode> GetCountryList()
{
    ICountryCodeRepository repo = ObjectFactory.GetInstance<ICountryCodeRepository>();
    IEnumerable<CountryCode> countries = repo.GetAll();
    return countries;
}

如您所见,这直接从 ObjectFactory 创建了一个 repo 对象。现在的问题是,当我想对控制器进行单元测试时,我可以模拟控制器的存储库,但不能模拟实用程序类中的存储库(控制器最终调用它)我确信还有其他原因我的实用程序类是错误的,但这是我目前看到的。我也读过一些东西说我的设计很糟糕,我只是不知道如何解决它。

我正在考虑让 GetCountryList() 函数接受一个 repo 对象

GetCountryList(ICountryCodeRepository _repo)

并且调用控制器会将其传入,但这不只是创建另一个依赖关系问题,因为所有控制器都必须知道实用程序函数需要什么?

或者是否有可能以某种方式使用 StructureMap 来注入这些实用程序方法?

4

1 回答 1

2

至少你知道你在做的是糟糕的设计是可以的。没关系,阅读这篇文章的人也会知道这一点,并避免和你犯同样的错误。

但现在,您可以在静态类中使用提供程序:

public static class Foo
{
    public static Func<ICountryCodeRepository> CountryRepoProvider = 
        () => ObjectFactory.GetInstance<ICountryCodeRepository>();

    public static IEnumerable<CountryCode> GetCountryList()
    {
        return CountryRepoProvider().GetAll();
    }
}

现在在你的单元测试中你可以模拟它:

Foo.CountryRepoProvider = () => mocha; 

或者,如果您使用的是 ASP.NET MVC 3 并且您的 DI 框架使用依赖解析器,您可以通过至少使其与 DI 框架无关来改进此代码:

public static IEnumerable<CountryCode> GetCountryList()
{
    var repo = DependencyResolver.Current.GetService<ICountryCodeRepository>();
    return repo.GetAll();
}

现在在您的单元测试中,您当然可以编写一个自定义依赖解析器,它将吐出您的服务的模拟实例。

现在,当您查看这段代码时,您可能真的会对自己说:我在做什么我正在编写一个静态类,其中一个班轮方法委托给我从 DI 获取的存储库。当我可以从我的 DI 框架中受益,在我需要的地方直接注入这个存储库的实例,然后简单地调用我需要的方法时,这有什么意义呢?我在那些单行静态方法中进行什么单元测试?我为什么要浪费时间

当然,如果您有更复杂的逻辑要处理,您只需编写一个服务层,它将必要的存储库作为构造函数依赖项并对其执行复杂的业务操作。然后,您将简单地配置您的 DI 框架,将那些准备好使用的服务实例注入您的控制器或您需要的任何地方。看?不需要任何静态类。弱耦合和单元测试友好的代码。

于 2012-06-28T16:38:54.920 回答