2011-08-04 26 views
6

Vi esto al usar picocontainer. Dicen que debes evitar los singletons. porque el patrón de Singleton hace que sea casi imposible que la clase (y posiblemente todas las otras clases que dependen de ella) puedan probarse. Es muy difícil crear una subclase o crear un objeto simulado para una clase Singleton.Pruebas de Singletons y subclases

Pero si realmente lo necesita, ¿hay alguna solución para el problema de las pruebas y las subclases?

Respuesta

5

Lo que hace que sea difícil probar singletons es el código que impone su singleton-ness (es decir, el modelo public static MySingleton getInstance() {...}). El uso de un contenedor de inversión de control, como PicoContainer o Guice o Spring, quita esa preocupación desde el objeto, por lo que ahora:

colaboradores
  • Puede ser instanciados y ha enchufado en él en las pruebas sin un problema.

  • El código que llama a un singleton no tiene que saber qué clase está buscando (lo que necesitaría saber si tuviera que llamar a un método estático).

Interpreto el consejo en el sitio web de picocontainer como algo similar. Lo que le están diciendo es que deje que nuestro contenedor administre el alcance de sus componentes por usted, no conecte con cable el código de aplicación del alcance.

+0

Perfectamente correcto - IOC es el camino a seguir para estas cosas –

1

si debe tener hijos únicos:

  1. tener una interfaz que describe cada Singleton
  2. Accede a tus hijos únicos de un/Singleton ServiceLocator
  3. Global Switch los casos registrados en el ServiceLocator durante las pruebas

Ejemplo:

interface IBankApi 
{ 
    public void MakeDeposity(int accountNumber, int dollarAmount); 
    // ... 
} 

public class RealBankApi : IBankApi { ... } 

// startup code 
serviceLocator.Register<IBankApi>(new RealBankApi()); 

// code using the API 
serviceLocator.Resolve<IBankApi>().MakeDeposit(...); 

// test code setup 
class FakeBankApi : IBankApi { ... } 
serviceLocator.Register<IBankApi>(new FakeBankApi()); 
1

El uso de IOC (inversión de control) en lugar de los singleton iniciados en el primer uso es ventajoso por otras razones también.

La inicialización de un soloton puede sufrir (famoso) problemas de multi-threading donde dos hilos intentan acceder a él por primera vez simultáneamente. Es probable que el acceso posterior se sincronice correctamente, pero el primero es mucho más difícil de hacer.

Otra gran ventaja que he encontrado al usar IOC es cuando puede ocurrir un error en la inicialización. No quiere que esto suceda con el "primer uso", quiere saber de esta falla en una etapa temprana, y ciertamente es más fácil manejar el error de esta manera.

Finalmente, con respecto a las pruebas, IOC proporciona el modelo perfecto para aislar componentes, sustituirlos según sea necesario y reunir diferentes combinaciones de una manera más flexible, proporcionando así el arnés perfecto para pruebas unitarias y pruebas de integración, como así como un buen mecanismo de reversión sin tener que revertir ningún código en absoluto.

La razón general por la cual los singletons se usan con tanta frecuencia no es por la unicidad sino por la globalidad. Si su proyecto se gestiona correctamente, tiene un único objeto global al que todos los demás "se registran" (por lo tanto, su modelo IOC se cuelga de él) y están disponibles globalmente mientras se siguen configurando.