65.9K
CodeProject 正在变化。 阅读更多。
Home

依赖注入与单元测试用例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (5投票s)

2014 年 12 月 26 日

CPOL

3分钟阅读

viewsIcon

24711

downloadIcon

99

通过一个简单的实际示例解释了依赖项的目的和实现。

引言

如今,依赖注入是面向对象编程中一个非常常用的术语。DI 是一种用于实现松耦合组件的设计模式。主要目的是代码可维护性和可重用性。您可能也听说过依赖注入容器,如 Unity、Ninject 或 Spring,但依赖注入是一个简单的概念,可以在任何地方使用,无需任何依赖注入容器,并且在单元测试中特别有用。

目标

在本文中,我们将涵盖

  • 依赖注入的实现和优点
  • 它如何简化编写测试用例

为了解释 DI,让我们以 Plane 为例。 Plane 可以有多个类,即 BusinessPremiumEconomy。现在假设所有这些类都实现一个接口 ItravelClass

public interface ITravelClass {      
}
public class Business : ITravelClass {
}
public class Economy: ITravelClass {
}
public class Premium : ITravelClass {
}

现在要实现一个带商务舱的飞机,我们可以这样写

public class Plane {
private Business businessClass;
}

这是一架不错的 plane,这个 plane 类与 Business 类紧密耦合。这没什么问题,Business 飞机很好,但如果我们决定允许 economy 类呢。然后我们必须修改这个类并添加 Economy 类的引用,这显然不是一个好方法。

使用接口

由于 Business 类实现了 ItravelClass 接口。其他类也实现了相同的接口。让我们思考一下。当我们设计 Plane 类时,我们可以在这里实例化 IteravelClass 的对象。让我们这样做

public class Plane {
private ITravelClass travelclass ;
}

但这只是一个接口,缺少一个具体类,所以我们必须实例化商务类的对象,如下所示

public class Plane {
private ITravelClass travelclass = new Business();
}

现在,这里我们使用接口,但它仍然有业务对象,仍然是紧密耦合。我们的问题仍然没有解决。

依赖注入

顾名思义,它都是关于注入依赖项并使类松耦合。这意味着我们必须使 Plane 类独立于具体类,并让它在运行时决定具体类的实现。

基于构造函数的注入

注入依赖项的一种方法是将依赖类的具体实现传递给构造函数。我们的 plane 类将变为

public class Plane {

private ITravelClass travelclass;

        public Plane(ITravelClass travelclass){
            this.travelclass = travelclass;
        }  
} 

现在,我们可以通过从客户端传递具体类来创建带有任何类的 plane。例如

class Program{

        //constructor based DI client

        static void Main(string[] args){

            //constructor based DI client
            Plane myBusinessPlane = new Plane(new Business());
            myBusinessPlane.setClass(new Business());
            Plane myEconomyPlane = new Plane(new Economy());
             myEconomyPlane.setClass(new Business());
            Console.ReadLine();
        }      
    }

基于属性的注入

我们还可以通过在 plane 类中使用 setter 来注入依赖项,如下所示

public class Plane{      

 private ITravelClass travelclass;

      public ITravelClass planeclass { 
        get {return travelclass ;}
        set { travelclass = value;}
      }

}

客户端的实现将相应更改

class Program
    {
        //DI using setter

        static void Main(string[] args){
            Plane myBusinessPlane = new Plane();
            myBusinessPlane.planeclass = new Business();
            Console.WriteLine(myBusinessPlane.planeclass.getServices());
            Console.WriteLine("---------------------------------");
            Plane myEconomyPlane = new Plane();
            myEconomyPlane.planeclass = new Economy();
            Console.WriteLine(myEconomyPlane.planeclass.getServices());
            Console.ReadLine();
    }

单元测试:依赖注入的用例

到目前为止,我们已经看到了如何实现依赖注入。现在,这样做有什么好处。一个是我们已经从 Plane 类中删除了紧密耦合。现在,依赖注入的一个实际的、经常使用的用例是在编写单元测试用例时。在上面的例子中,我们使用了没有任何复杂实现的简单类。让我们更改 ITravelClass 并添加两个方法 SetClassgetServices,并在其他类中实现这些方法。

void setClass(String classtype, String priceRange);
String getServices();

假设在实际示例中,这些方法可能涉及一些复杂的数据库操作,我们不希望在我们的测试用例中使用这些操作。所以我们可以创建一个模拟类来实现 ITravelClass 并在方法中拥有我们自己的测试数据。

public class MockClass :ITravelClass
    {
        private String classtype = "MockClass";
        private String priceRange = "TEST data";

        public void setClass(String classtype, String priceRange)
        {
            this.classtype = classtype;
            this.priceRange = priceRange;
        }
        public String getServices()
        {
            return classtype;
        }
    }

单元测试类的实现如下所示

[TestClass]

    public class ProgramTest
    {
        [TestMethod]
        public void TestPlane(){
            Plane myMockPlane = new Plane();
             myMockPlane.planeclass  = new MockClass(); 
            Assert.AreEqual("MockClass", myMockPlane.planeclass.getServices());
        }
    }

所以现在我们已经实现了依赖注入,并成功地将其用于单元测试用例。总而言之,我们涵盖的一些重要点如下

  • 使用接口而不是具体类来避免类中依赖项的紧密耦合。
  • 依赖注入可以通过多种方式完成,例如构造函数注入或属性 setter 注入。
  • 依赖注入使单元测试非常灵活。

对于完整的实现,请下载附加的代码。

© . All rights reserved.