2011-01-23 6 views
6

Estoy aprendiendo TDD. Sé acerca de la inyección de dependencia mediante el cual se colocan las dependencias de la clase en los parámetros del constructor y se pasan, pasando por implementaciones predeterminadas del constructor predeterminado, por ejemplo;¿Las clases de prueba de unidad en el proyecto web ASP.NET MVC son un buen ejemplo?

public AccountController() : this(RepositoryFactory.Users()) 
{ 
} 

public AccountController(IUserRepository oUserRepository) 
{ 
m_oUserRepository = oUserRepository; 
} 

RepositoryFactory es una clase estática simple que devuelve las implementaciones elegidos para la versión actual

Sin embargo, el proyecto de aplicación web por defecto ASP.NET MVC no hace esto, en lugar de la DI se presenta en forma de público propiedades que se asignan en el inicializador de objetos en la clase de prueba, por ejemplo; de AccountController.cs:

protected override void Initialize(RequestContext requestContext) 
{ 
if (FormsService == null) 
    { FormsService = new FormsAuthenticationService(); } 
if (MembershipService == null) 
    { MembershipService = new AccountMembershipService(); } 

base.Initialize(requestContext); 
} 

y en el AccountControllerTest.cs clase de prueba:

private static AccountController GetAccountController() 
{ 
AccountController controller = new AccountController() 
{ 
    FormsService = new MockFormsAuthenticationService(), 
    MembershipService = new MockMembershipService(), 
    Url = new UrlHelper(requestContext), 
}; 
//snip 
} 

Así que ahora mi clase AccountController tiene dos enfoques para la inyección de dependencias. ¿Cuál debería usar? Constructor inyección o propiedades públicas?

pienso constructor de inyección ...

es el uso de ASP.NET MVC propiedades públicas así porque es necesario para proporcionar una forma específica de la inyección en el constructor, y el básico "Crear nueva" aplicación web debe ser genérico como punto de partida?

Respuesta

11

Los ejemplos en el ASP.NET MVC son excelentes demostraciones de cómo no de usar DI.

En primer lugar, usar un constructor predeterminado así como un constructor sobrecargado introduce ambigüedad: ¿la clase controla sus propias dependencias, o las obtiene desde el exterior? Aparentemente, no puede decidir realmente.

En segundo lugar, tener una implementación predeterminada introduce acoplamiento cerrado porque no puede crear una nueva instancia de la implementación predeterminada sin tener una referencia a la misma. Sin embargo, el whole point of DI is to enable loose coupling.

Lamentablemente, vemos este modismo mucho. En my book lo llamo Bastard Injection pattern; Levanté el nombre de una de las muchas publicaciones del blog Oren Eini/Ayende Rahien donde he walks through a very similar example.

Como consejo general, recomiendo usar Constructor Injection en la gran mayoría de los casos. Es fácil de implementar y tiene una semántica muy sólida: obliga al consumidor a suministrar una instancia de la dependencia, declarando efectivamente que la dependencia es obligatoria.

La inyección de propiedad, por otro lado, implica que la dependencia es opcional, porque el compilador no lo obliga a asignar un valor. En la mayoría de los casos, las dependencias no son realmente opcionales, por lo que el uso de este patrón debería ser raro.

+0

Gracias Mark, tiene sentido ahora.¿Es ambigua o conveniente? Para los controladores solo veo dos usos (en mi ignorancia probablemente); la aplicación compilada y el proyecto de prueba. La aplicación compilada solo usa las implementaciones predeterminadas del constructor predeterminado. Eso será más rápido que usar un contenedor de IOC ¿no? –

+0

Ah ok, creo que lo entiendo. Estoy leyendo sobre IOC anidado donde una dependencia tiene dependencias. Con IOC esto se resuelve con una sola línea como IoC.Resolve (); –

+0

Mark, ¿me pueden ayudar a entender mejor por qué no utilizar "Inyección Bastard"? Como yo lo veo, la clase todavía permite el acoplamiento libre en el que no tienes que usar el constrcutor por defecto. Es cierto que el código tiene una dependencia estática en RepositoryFactory, pero no es necesario que lo use. Además, la "ambigüedad" es una característica: use las dependencias predeterminadas o inserte las suyas propias. ¿Qué está mal con eso? –

Cuestiones relacionadas