Pregunta ¿Qué es la inyección de dependencia?


Ha habido varias preguntas ya publicadas con preguntas específicas sobre inyección de dependencia, como cuándo usarlo y qué marcos hay para ello. Sin embargo,

¿Qué es la inyección de dependencia y cuándo / por qué debería o no debería usarse?


2626
2017-09-25 00:28


origen


Respuestas:


Básicamente, en lugar de tener tus objetos creando una dependencia o pidiéndole a un objeto de fábrica que haga una para ellos, pasas las dependencias necesarias al objeto externamente, y lo conviertes en un problema ajeno. Este "alguien" es un objeto más arriba en el gráfico de dependencia, o un inyector de dependencia (marco) que construye el gráfico de dependencia. Una dependencia como la estoy usando aquí es cualquier otro objeto al que el objeto actual necesita contener una referencia.

Una de las principales ventajas de la inyección de dependencia es que puede facilitar mucho las pruebas. Supongamos que tiene un objeto que en su constructor hace algo como:

public SomeClass() {
    myObject = Factory.getObject();
}

Esto puede ser problemático cuando todo lo que quiere hacer es ejecutar algunas pruebas de unidad en SomeClass, especialmente si myObject es algo que hace acceso complejo a disco o red. Entonces ahora estás viendo burlarse de myObject pero también de alguna manera interceptando la llamada de fábrica. Difícil. En cambio, pase el objeto como un argumento al constructor. Ahora ha trasladado el problema a otro lugar, pero las pruebas pueden ser mucho más fáciles. Simplemente crea un dummy myObject y pásalo. El constructor se vería un poco como:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Este es un estilo de inyección de dependencia: a través del constructor. Varios mecanismos son posibles.

  • Como se señaló en los comentarios, una alternativa común es definir un constructor de hacer nada y tener las dependencias inyectadas a través de los establecedores de propiedades (h / t @MikeVella).
  • Martin Fowler documenta una tercera alternativa (h / t @MarcDix), donde las clases implementan explícitamente una interfaz para las dependencias que desean inyectar.

Cuando no se utiliza la inyección de dependencia (como en las clases que hacen demasiado trabajo en sus constructores, etc.), tiende a ser mucho más difícil aislar los componentes en las pruebas unitarias.

En el año 2013, cuando escribí esta respuesta, este fue un tema importante en el Blog de prueba de Google. Esta sigue siendo la mayor ventaja para mí, ya que no siempre necesitará la flexibilidad adicional en su diseño en tiempo de ejecución (por ejemplo, para el localizador de servicios o patrones similares), pero a menudo necesita poder aislar sus clases durante la prueba.


1633
2017-09-25 00:49



La mejor definición que he encontrado hasta ahora es uno por James Shore:

"Inyección de dependencia" es un dólar de 25 dólares   término para un concepto de 5 centavos. [...]   Inyección de dependencia significa dar una   objetar sus variables de instancia. [...].

Ahi esta un artículo de Martin Fowler eso puede ser útil, también.

La inyección de dependencia básicamente proporciona los objetos que un objeto necesita (sus dependencias) en lugar de tener que construirlos por sí mismo. Es una técnica muy útil para las pruebas, ya que permite burlar o anular las dependencias.

Las dependencias se pueden inyectar en los objetos de muchas maneras (como la inyección de constructor o la inyección de setter). Incluso se pueden usar marcos de inyección de dependencia especializados (por ejemplo, Spring) para hacer eso, pero ciertamente no son necesarios. No necesita esos marcos para tener inyección de dependencia. Instanciar y pasar objetos (dependencias) explícitamente es una inyección tan buena como la inyección por marco.


2058
2017-09-26 16:50



Encontré este divertido ejemplo en términos de bajo acoplamiento:

Cualquier aplicación se compone de muchos objetos que colaboran entre sí para realizar algunas cosas útiles. Tradicionalmente, cada objeto es responsable de obtener sus propias referencias a los objetos dependientes (dependencias) con los que colabora. Esto lleva a clases altamente acopladas y código difícil de probar.

Por ejemplo, considere una Car objeto.

UN Car depende de las ruedas, el motor, el combustible, la batería, etc. para funcionar. Tradicionalmente, definimos la marca de dichos objetos dependientes junto con la definición del Car objeto.

Sin Inyección de Dependencia (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Aquí el Car objeto es responsable de crear los objetos dependientes.

¿Qué pasa si queremos cambiar el tipo de su objeto dependiente? Wheel - después de la inicial NepaliRubberWheel() pinchazos? Necesitamos recrear el objeto Car con su nueva dependencia decir ChineseRubberWheel(), pero solo el Car el fabricante puede hacer eso.

Entonces, ¿qué hace el Dependency Injection haznos por ...?

Al usar la inyección de dependencia, los objetos reciben sus dependencias en tiempo de ejecución en lugar de tiempo de compilación (tiempo de fabricación del automóvil). Para que ahora podamos cambiar el Wheel cuando queramos Aquí el dependency (wheel) se puede inyectar en Car en tiempo de ejecución.

Después de usar la inyección de dependencia:

Aquí estamos inyectar el dependencias (Rueda y batería) en tiempo de ejecución. De ahí el término: Inyección de dependencia. 

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Fuente: Entender la inyección de dependencia


507
2018-05-22 04:01



La Inyección de Dependencia es una práctica en la que los objetos se diseñan de manera tal que reciben instancias de los objetos de otros fragmentos de código, en lugar de construirlos internamente. Esto significa que cualquier objeto que implemente la interfaz requerida por el objeto puede ser sustituido sin cambiar el código, lo que simplifica las pruebas y mejora el desacoplamiento.

Por ejemplo, considere estas clases:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

En este ejemplo, la implementación de PersonService::addManager y PersonService::removeManager necesitaría una instancia del GroupMembershipService para hacer su trabajo. Sin Inyección de Dependencia, la forma tradicional de hacerlo sería crear una nueva instancia GroupMembershipService en el constructor de PersonService y use ese atributo de instancia en ambas funciones. Sin embargo, si el constructor de GroupMembershipService tiene varias cosas que requiere, o peor aún, hay algunos "setters" de inicialización que necesitan ser llamados en el GroupMembershipService, el código crece bastante rápido, y el PersonServiceahora depende no solo del GroupMembershipService sino también todo lo demás que GroupMembershipService depende de. Además, el vínculo a GroupMembershipService está codificado en el PersonService lo que significa que no puedes "fingir" un GroupMembershipService para fines de prueba o para usar un patrón de estrategia en diferentes partes de su aplicación.

Con Dependency Injection, en lugar de instanciar el GroupMembershipService dentro de tu PersonService, lo pasarías a la PersonService constructor, o bien agregue una propiedad (getter y setter) para establecer una instancia local de la misma. Esto significa que su PersonService ya no tiene que preocuparse por cómo crear un GroupMembershipService, solo acepta los que se le dan y trabaja con ellos. Esto también significa que cualquier cosa que sea una subclase de GroupMembershipService, o implementa el GroupMembershipService la interfaz puede ser "inyectada" en el PersonService, y el PersonService no necesita saber sobre el cambio.


233
2017-09-25 06:49



La respuesta aceptada es buena, pero me gustaría añadir que DI es muy parecido al clásico evitar las constantes codificadas en el código.

Cuando usa alguna constante como el nombre de una base de datos, la mueve rápidamente desde el interior del código a algún archivo de configuración y pasa una variable que contiene ese valor al lugar donde se necesita. La razón para hacerlo es que estas constantes generalmente cambian con más frecuencia que el resto del código. Por ejemplo, si desea probar el código en una base de datos de prueba.

DI es análogo a esto en el mundo de la programación orientada a objetos. Los valores allí en lugar de literales constantes son objetos completos, pero la razón para mover el código que los crea del código de clase es similar: los objetos cambian con más frecuencia que el código que los usa. Un caso importante en el que se necesita tal cambio son las pruebas.


142
2018-01-06 18:33



Imaginemos que quiere ir de pesca:

  • Sin la inyección de dependencia, debe encargarse de todo usted mismo. Necesitas encontrar un bote, comprar una caña de pescar, buscar carnada, etc. Es posible, por supuesto, pero te da mucha responsabilidad. En términos de software, significa que debe realizar una búsqueda de todas estas cosas.

  • Con la inyección de dependencia, alguien más se ocupa de toda la preparación y pone a su disposición el equipo necesario. Recibirás ("serás inyectado") el bote, la caña de pescar y el cebo, todo listo para usar.


96
2017-10-22 04:47



Esta es la explicación más simple sobre Inyección de dependencia y Envase de inyección de dependencia Alguna vez he visto:

Sin inyección de dependencia

  • La aplicación necesita Foo (por ejemplo, un controlador), así que:
  • La aplicación crea Foo
  • Llamadas de aplicación Foo
    • Foo necesita barra (por ejemplo, un servicio), entonces:
    • Foo crea Bar
    • Foo llama a Bar
      • Bar necesita Bim (un servicio, un repositorio, …), asi que:
      • Bar crea Bim
      • Bar hace algo

Con Inyección de Dependencia

  • La aplicación necesita Foo, que necesita Bar, que necesita Bim, así que:
  • La aplicación crea Bim
  • La aplicación crea Bar y le da Bim
  • La aplicación crea Foo y le da Bar
  • Llamadas de aplicación Foo
    • Foo llama a Bar
      • Bar hace algo

Uso de un contenedor de inyección de dependencias

  • La aplicación necesita Foo así que:
  • La aplicación obtiene Foo del contenedor, entonces:
    • El contenedor crea Bim
    • El contenedor crea Bar y lo da Bim
    • El contenedor crea Foo y le da Bar
  • Llamadas de aplicación Foo
    • Foo llama a Bar
      • Bar hace algo

Inyección de dependencia y Contenedores de inyección de dependencia son cosas diferentes:

  • Dependency Injection es un método para escribir un código mejor
  • un DI Container es una herramienta para ayudar a inyectar dependencias

No necesita un contenedor para hacer una inyección de dependencia. Sin embargo, un contenedor puede ayudarte.


80
2018-05-05 11:53



Probemos un simple ejemplo con Coche y Motor clases, cualquier automóvil necesita un motor para ir a cualquier parte, al menos por ahora. Por debajo de cómo se verá el código sin inyección de dependencia.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

Y para crear una instancia de la clase Car usaremos el siguiente código:

Car car = new Car();

El problema con este código que estrechamente unimos a GasEngine y si decidimos cambiarlo a ElectricityEngine, entonces necesitaremos reescribir la clase de Auto. Y cuanto más grande sea la aplicación, más problemas y dolores de cabeza tendremos que agregar y usar un nuevo tipo de motor.

En otras palabras, con este enfoque es que nuestra clase de automóvil de alto nivel depende de la clase GasEngine de nivel inferior que viola el Principio de Inversión de Dependencia (DIP) de SOLID. DIP sugiere que debemos depender de abstracciones, no de clases concretas. Para satisfacer esto, presentamos la interfaz de IEngine y reescribimos el código como se muestra a continuación:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Ahora nuestra clase de Auto depende de la interfaz IEngine, no de una implementación específica del motor. Ahora, el único truco es cómo creamos una instancia del automóvil y le damos una clase real concreta de motores como GasEngine o ElectricityEngine. Ahí es donde Inyección de dependencia viene en.

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Aquí básicamente inyectamos (pasamos) nuestra dependencia (instancia del motor) al constructor del coche. Así que ahora nuestras clases tienen un acoplamiento flexible entre los objetos y sus dependencias, y podemos agregar fácilmente nuevos tipos de motores sin cambiar la clase de Auto.

El principal beneficio de la Inyección de dependencia que las clases están más débilmente acopladas, porque no tienen dependencias codificadas. Esto sigue el Principio de Inversión de Dependencia, que se mencionó anteriormente. En lugar de hacer referencia a implementaciones específicas, las clases solicitan abstracciones (generalmente interfaces) que se les proporcionan cuando se construye la clase.

Entonces al final Inyección de dependencia es solo una técnica para   logrando un acoplamiento flexible entre los objetos y sus dependencias.   En lugar de instanciar directamente dependencias que la clase necesita en   Para realizar sus acciones, se proporcionan dependencias a la clase   (más a menudo) a través de la inyección de constructor.

Además, cuando tenemos muchas dependencias, es una buena práctica usar contenedores de Inversión de Control (IoC) que nos permiten saber qué interfaces se deben mapear para qué implementaciones concretas para todas nuestras dependencias y podemos hacer que resuelvan esas dependencias cuando se construyen. nuestro objeto Por ejemplo, podríamos especificar en la asignación para el contenedor IoC que el IEngine la dependencia debe ser mapeada a la Motor de gas clase y cuando solicitamos el contenedor IoC para una instancia de nuestra Coche clase, construirá automáticamente nuestra Coche clase con un Motor de gas la dependencia pasó.

ACTUALIZAR: Observé el curso sobre EF Core de Julie Lerman recientemente y también me gustó su breve definición sobre DI.

La inyección de dependencia es un patrón para permitir que su aplicación se inyecte   objetos sobre la marcha a las clases que los necesitan, sin forzarlos   clases para ser responsable de esos objetos. Permite que tu código sea   más débilmente acoplado, y Entity Framework Core se conecta a este mismo   sistema de servicios.


77
2017-07-06 09:42



¿La "inyección de dependencia" no significa simplemente usar constructores parametrizados y establecedores públicos?

El artículo de James Shore muestra los siguientes ejemplos de comparación.

Constructor sin inyección de dependencia:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

Constructor con inyección de dependencia:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}

44
2018-05-02 00:40



¿Qué es la Inyección de Dependencia (DI)?

Como otros han dicho, Inyección de Dependencia (DI) elimina la responsabilidad de la creación directa y la gestión de la vida útil de otras instancias de objetos de las que depende nuestra clase de interés (clase de consumidor) (en el Sentido de UML) En su lugar, estas instancias se pasan a nuestra clase de consumidor, generalmente como parámetros de constructor o mediante el establecimiento de propiedades (la administración de la creación de instancias de objeto de dependencia y el paso a la clase de consumidor generalmente se realiza por un Inversión de control (IoC) contenedor, pero ese es otro tema).

DI, DIP y SÓLIDO

Específicamente, en el paradigma de Robert C Martin's Principios SÓLIDOS de Diseño Orientado a Objetos, DI es una de las posibles implementaciones de la Principio de Inversión de Dependencia (DIP). los DIP es el D del SOLID mantra  - otras implementaciones de DIP incluyen el localizador de servicios y los patrones de complementos.

El objetivo del DIP es desacoplar dependencias estrechas y concretas entre clases, y en su lugar, aflojar el acoplamiento mediante una abstracción, que se puede lograr a través de un interface, abstract class o pure virtual class, según el idioma y el enfoque utilizado.

Sin el DIP, nuestro código (he llamado a esto 'clase consumidora') está directamente acoplado a una dependencia concreta y también suele estar cargado con la responsabilidad de saber cómo obtener y gestionar una instancia de esta dependencia, es decir, conceptualmente:

"I need to create/use a Foo and invoke method `GetBar()`"

Mientras que después de la aplicación del DIP, el requisito se afloja, y la preocupación de obtener y administrar la vida útil del Foo la dependencia ha sido eliminada:

"I need to invoke something which offers `GetBar()`"

¿Por qué usar DIP (y DI)?

Desacoplando dependencias entre clases de esta manera permite fácil sustitución de estas clases de dependencia con otras implementaciones que también cumplen con los requisitos previos de la abstracción (por ejemplo, la dependencia puede cambiarse con otra implementación de la misma interfaz). Además, como otros han mencionado, posiblemente el La razón más común para desacoplar clases a través del DIP es permitir que una clase consumidora sea probada de forma aislada, ya que estas mismas dependencias ahora pueden ser anuladas y / o burladas.

Una consecuencia de DI es que la gestión de la vida útil de las instancias de objetos de dependencia ya no está controlada por una clase consumidora, ya que el objeto de dependencia pasa ahora a la clase consumidora (a través de la inyección de constructor o instalador).

Esto se puede ver de diferentes maneras:

  • Si se necesita retener el control de las dependencias por parte de la clase consumidora, se puede restablecer el control inyectando una fábrica (abstracta) para crear las instancias de clase de dependencia en la clase de consumidor. El consumidor podrá obtener instancias a través de un Create en la fábrica según sea necesario, y elimine estas instancias una vez completadas.
  • O bien, el control de la duración de las instancias de dependencia puede cederse a un contenedor IoC (más información sobre esto a continuación).

Cuándo usar DI?

  • Donde es probable que haya una necesidad de sustituir una dependencia por una implementación equivalente,
  • En cualquier momento en que necesite probar los métodos de una clase en forma aislada de sus dependencias,
  • Donde la incertidumbre de la duración de una dependencia puede justificar la experimentación (por ejemplo, Hey, MyDepClass es seguro para subprocesos, ¿qué pasa si lo convertimos en un singleton e inyectamos la misma instancia en todos los consumidores?)

Ejemplo

Aquí hay una implementación simple de C #. Dada la siguiente clase de consumo:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Aunque aparentemente inocuo, tiene dos static dependencias en otras dos clases, System.DateTime y System.Console, lo que no solo limita las opciones de salida del registro (el inicio de sesión en la consola no valdrá nada si nadie está mirando), sino que es más difícil probarlo automáticamente dada la dependencia de un reloj del sistema no determinista.

Sin embargo, podemos aplicar DIP a esta clase, al abstraer la preocupación del sellado de tiempo como una dependencia, y el acoplamiento MyLogger solo a una interfaz simple:

public interface IClock
{
    DateTime Now { get; }
}

También podemos aflojar la dependencia de Console a una abstracción, como una TextWriter. La Inyección de Dependencia se implementa típicamente como cualquiera constructor inyección (pasando una abstracción a una dependencia como parámetro para el constructor de una clase consumidora) o Setter Injection (pasando la dependencia a través de setXyz() setter o una propiedad .Net con {set;} definido). Se prefiere la inyección de constructores, ya que esto garantiza que la clase estará en un estado correcto después de la construcción, y permite que los campos de dependencia interna se marquen como readonly (C #) o final (Java). Entonces, usando la inyección de constructor en el ejemplo anterior, esto nos deja con:

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(Un concreto Clock necesita ser provisto, que por supuesto podría volver a DateTime.Now, y las dos dependencias deben ser proporcionadas por un contenedor IoC mediante inyección de constructor)

Se puede construir una Prueba de Unidad automatizada, que definitivamente demuestra que nuestro registrador está funcionando correctamente, ya que ahora tenemos control sobre las dependencias, el tiempo, y podemos espiar el resultado escrito:

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

Próximos pasos

La inyección de dependencia está invariablemente asociada a una Inversión del contenedor de control (IoC), para inyectar (proporcionar) las instancias de dependencia concretas y para administrar instancias de vida útil. Durante el proceso de configuración / arranque, IoC los contenedores permiten definir lo siguiente:

  • mapeo entre cada abstracción y la implementación concreta configurada (p. "cada vez que un consumidor solicita un IBar, devuelve un ConcreteBar ejemplo")
  • las políticas se pueden configurar para la gestión de la vida útil de cada dependencia, p. crear un nuevo objeto para cada instancia de consumidor, compartir una instancia de dependencia de singleton en todos los consumidores, compartir la misma instancia de dependencia solo en el mismo subproceso, etc.
  • En .Net, los contenedores IoC conocen protocolos como IDisposable y asumirá la responsabilidad de Disposing dependencias en línea con la gestión de la vida útil configurada.

Típicamente, una vez que los contenedores de IoC se han configurado / bootstrap, operan perfectamente en el fondo, lo que permite al codificador enfocarse en el código que tiene a mano en lugar de preocuparse por las dependencias.

La clave del código compatible con DI es evitar el acoplamiento estático de clases y no usar new () para la creación de dependencias.

Como en el ejemplo anterior, el desacoplamiento de dependencias requiere algún esfuerzo de diseño, y para el desarrollador, se necesita un cambio de paradigma para romper el hábito de newdirectamente las dependencias y, en su lugar, confiando en que el contenedor administre las dependencias.

Pero los beneficios son muchos, especialmente en la capacidad de probar a fondo su clase de interés.

Nota : La creación / mapeo / proyección (a través de new ..()) de POCO / POJO / DTO de serialización / Gráficos de entidad / proyecciones JSON anónimas y otros, es decir, "clases o registros" solo de datos ", que se utilizan o devuelven de los métodos. no considerados como Dependencias (en el sentido UML) y no sujetos a DI. Utilizando new proyectar esto está bien.


35
2018-04-28 20:17



Para hacer que el concepto de Inyección de Dependencia sea simple de entender. Tomemos un ejemplo del botón de cambio para alternar (encender / apagar) una bombilla.

Sin inyección de dependencia

Switch necesita saber de antemano a qué bombilla estoy conectado (dependencia codificada). Asi que,

Cambiar -> PermanentBulb // el interruptor está directamente conectado al bulbo permanente, las pruebas no son fáciles de realizar

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

Con Inyección de Dependencia

Switch solo sabe que necesito activar / desactivar el Bulbo que se me pase. Asi que,

Cambiar -> Bulb1 O Bulb2 O NightBulb (dependencia inyectada)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

Modificando James Ejemplo para interruptor y bombilla:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`

30
2017-10-28 20:30