My ExampleViewModel
has a parameter (a model) that it needs to function properly. I also have a list variant of the ExampleViewModel
that just contains a ObservableCollection<ExampleViewModel>
and has some wrapper methods.
The issue shows it self when I try to use dependency injection with MVVM Light. Let me explain the scenario with some code.
default ViewModelLocator:
public class ViewModelLocator {
public ViewModelLocator() {
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic) {
SimpleIoc.Default.Register<IDataService, DesignDataService>();
} else {
SimpleIoc.Default.Register<IDataService, DataService>();
}
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main {
get {
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup() {}
}
Simple MainViewModel:
public class MainViewModel : ViewModelBase {
private IDataService _service;
private MainModel _model;
// Goal. I think?
public MainViewModel(IDataService service, MainModel model) {
_service = service;
_model = model;
}
// Used now
public MainViewModel(MainModel model) {
_service = ServiceLocator.Current.GetInstance<IDataService>();
_model = model;
}
}
And the ListMainViewModel fills it's list like this:
Mains = new ObservableCollection<MainViewModel>(
_service.GetAll().Select(model => new MainViewModel(model))
);
Because of the list creation in the ListMainViewModel
I can't inject the data source in the constructor and have to use it as shown under // Used now
. Which is fine, but when I try to unit test problems occur, as you can probably imagine.
I use a unit test like this at the moment:
public void ListMainViewModel_DoSomething_Success() {
// Arrange
var mock = new Mock<IDataService>();
mock.Setup(m => m.Create(new MainModel { Naam = "Create" }));
mock.Setup(m => m.Update(new MainModel { Naam = "Update" }));
var listMainViewModel = new ListMainViewModel(mock.Object);
var selected = new MainModel() { Prop = "Test" };
listMainViewModel.SelectedMainViewModel = new MainViewModel(selected);
// Act
listMainViewModel.DoSomething();
// Assert
mock.Verify(x => listMainViewModel.DoSomething(), Times.Exactly(1));
}
Note: Not sure if the unit test is correct. But the problem occurs while creating the SelectedMainViewModel
because it doesn't fetch a DataService
.
For now I have two choices (I think), I can make the MainModel in MainViewModel optional, which is not something that should be possible and contructor inject the IDataService. Or I can discover a way to make the _service find-able by the MainViewModel.
Is there any elegant way to solve this? Because I have the feeling I have to make some hack using if (InDesignMode)
or something similar.