我如何处理抽象第三方依赖(依赖注入)?

时间:2012-08-08 22:56:06

标签: asp.net-mvc unit-testing architecture dependency-injection ninject

在将Ninject与ASP.NET MVC一起使用时,抽象第三方依赖项的最佳方法是什么?

通常,我会这样做:

public interface IProductRepository
{
    IEnumerable<Product> GetProducts();
}

public class ProductRespository : IProductRepository
{
    public IEnumerable<Product> GetProducts()
    {
        ...
    }
}

然后在控制器中:

public class ProductController : Controller
{
    private IProductRepository repository;

    public ProductController(IProductRepository repository)
    {
        this.repository = repository;
    }

    ...
}

然后我使用Ninject自动将固体ProductRepository注入控制器。

但如果依赖项是第三方,我该怎么做呢?例如,我正在使用FlickrNet

public class ProductController : Controller
{
    private Flickr flickr;

    ...
}

我希望能够将Flickr对象抽象到一个接口中,以便我可以使用依赖注入并使其更容易进行单元测试。我知道我可以创建一个“服务”类型的接口,然后实现一个基于包装Flickr对象的类。

但是我必须在界面中定义一个与Flickr对象的每个成员相对应的成员,然后在包装器对象中映射每个成员。 Flickr对象中有很多成员。

有没有更好的方法来解决这个问题?我的主要目标是在单元测试中轻松模拟Flickr依赖。

4 个答案:

答案 0 :(得分:3)

将我的评论升级为答案。

这不是DI的问题,而是一般的架构问题。您可以将控制器声明为抽象层,也可以定义实现自定义接口的flickr组件的包装器。如果你的第三方组件上的方法消耗了更多的第三方类,你也需要将它们抽象出去等等,直到你只使用原始值或更多第三方代码包装。根据该组件的复杂程度,这可能意味着大量的映射和包装。

答案 1 :(得分:2)

我认为包装是正确的方法。您不必公开第三方对象的每个成员 - 只需要您需要的那些成员。通过针对不同情况的不同接口,包装器解决方案变得更加漂亮。

答案 2 :(得分:1)

我知道这篇文章不是关于单元测试,但它提供的解决方案也适用于基于模拟的单元测试。

http://goodcoffeegoodcode.blogspot.com/2011_04_01_archive.html

基本上,正如@Brian Dishaw所说,你需要从FlickrNet类中提取接口并将它们注入到你的类中。

答案 3 :(得分:1)

唯一的目的是将flickr .NET抽象为更高的抽象层。例如

interface IAlbumViewer
{
   IEnumerable<IImage> GetImages();
}

interface IPictureUploader
{
   string Upload(string filename, Stream image)
}

也就是说,创建特定于您的用例的接口/方法与通用的flickr接口相反。您也可以从中受益,因为它可以更轻松地添加对其他图像服务的支持。