Estoy construyendo una aplicación similar a Visual Studio en WPF y tengo algunos problemas para identificar la mejor organización de diseño arquitectónico de mis componentes. Planeo usar Unity como mi contenedor de inyección de dependencias y el marco de prueba de la unidad de Visual Studio y, probablemente, moq para burlarse de la biblioteca.MVVM con diseño arquitectónico Unity and Unit Testing
voy a describir primero la estructura de mi solución, entonces mis preguntas:
Tengo un proyecto WPF que contiene:
- Mi inicialización contenedor Unidad (programa previo) al iniciar la aplicación (en App.xaml.cs)
- Todas mis vistas de aplicaciones (XAML).
otro proyecto llamado modelo de vista este contiene:
- Todos mis ViewModels aplicación. Todos mis ViewModels heredan de una ViewModelBase que expone una propiedad ILogger
Mi lógica de inicialización es el siguiente:
- Aplicación de inicio
- Unidad creación de contenedores y el registro de los tipos: MainView y MainViewModel
- Resuelve mi MainView y muéstralo.
var window = Container.Resolve<MainView>();
window.Show();
Mi constructor MainView recibe un objeto MainViewModel en su constructor:
public MainView(MainViewModel _mvm)
Mi MainViewModel tiene un modelo de vista del niño para cada uno de sus paneles:
public ToolboxViewModel ToolboxVM{get; set;} public SolutionExplorerViewModel SolutionExplorerVM { get; set; } public PropertiesViewModel PropertiesVM { get; set; } public MessagesViewModel MessagesVM { get; set; }
Y tengo la intención de crear un método InitializePanels() que inicializa cada uno de los paneles.
Ahora aquí mis preguntas: ¿Cómo puede mi MainViewModel.InitializePanels() inicializar todos esos paneles? Dadas las siguientes opciones:
Opción 1: inicializar el ViewModels manualmente:
ToolboxVM = new ToolboxViewModel();
//Same for the rest of VM...
Contras:
- no estoy usando el contenedor de la unidad para mis dependencias (por ejemplo,ILogger) no se resuelve automáticamente
Opción 2: Uso de inyección colocador anotando mis propiedades:
[Dependency]
public ToolboxViewModel ToolboxVM{get; set;}
//... Same for rest of Panel VM's
Contras:
- He leído que las dependencias de la Unidad Setter debe evitarse ya que generan una dependencia con Unity en este caso
- También leí que debe evitar el uso de Unity para las pruebas unitarias, entonces, ¿cómo hacer que esta dependencia quede clara en mis pruebas unitarias? Tener muchas propiedades dependientes podría ser una pesadilla para configurar.
Opción 3: Uso Unidad Constructor de inyección para pasar todos mis ViewModels panel al constructor MainViewModel por lo que se resuelven automáticamente por la Unidad de contenedores:
public MainViewModel(ToolboxViewModel _tbvm, SolutionExploerViewModel _sevm,....)
Pros:
- La dependencia sería evidente y clara en el momento de la creación, lo que podría ayudar a crear mis UnitTests de ViewModel.
Contras:
- tener tantos parámetros del constructor podrían ponerse feas con bastante rapidez
Opción 4: El registro de todos los tipos de máquinas virtuales en mis acumulación de contenedores. Luego de pasar la instancia UnityContainer través de la inyección de constructor a mi MainViewModel:
public MainViewModel(IUnityContainer _container)
De esa manera podría hacer algo como:
Toolbox = _container.Resolve<ToolboxViewModel>();
SolutionExplorer = _container.Resolve<SolutionExplorerViewModel>();
Properties = _container.Resolve<PropertiesViewModel>();
Messages = _container.Resolve<MessagesViewModel>();
Contras:
- Si decide no utilizar Unity para mis UnitTests, como muchas personas sugieren, entonces no podré resolver e inicializar mi Panel ViewModels.
Teniendo en cuenta esa larga explicación, ¿cuál es el mejor enfoque para poder aprovechar un Contenedor de Inyección de Dependencia y terminar con una solución Testable por la Unidad?
Gracias de antemano,
Tiene toda la razón. Debería codificar contra interfaces y no con implementaciones concretas, sin embargo, normalmente empiezo a codificar las clases concretas y luego extraigo sus interfaces con Resharper, todavía no he llegado a ese punto, ¡pero lo haré pronto! –
Mi solución rápida y sucia para esto es crear una instancia de mis modelos de vista en app.xaml como recursos, luego combinarlos según sea necesario. ' ' que hace que las pruebas unitarias sean fáciles de configurar. –
Will