5

I've created a custom view model locator using Autofac and set it up normally through the App.xaml like most of them are usually used. My problem is how do I unit test now? I'm getting an error every time I try to test a method that initializes a view

In my app.xaml:

<desktop:ViewModelLocator xmlns:local="clr-namespace:MyProject.Desktop" x:Key="ViewModelLocator" />

In each view:

DataContext="{Binding MyFirstViewModel, Source={StaticResource ViewModelLocator}}"

The Unit Test Error:

{"Cannot find resource named 'ViewModelLocator'. Resource names are case sensitive."}

I understand why cause when you unit test, there really isn't an instance of the actual App so what is a good way around this problem?

ViewModelLocator Code:

/// <summary>
/// Autofac object container
/// </summary>
private readonly IContainer objectContainer;

#region Constructor

/// <summary>
/// Constructor for view model locator
/// </summary>
public ViewModelLocator()
{
    objectContainer = App.ObjectContainer;
    //objectContainer.BeginLifetimeScope();
}

#endregion

#region Properties

/// <summary>
/// Gets the resolved instance of a main window view model
/// </summary>
public MainWindowViewModel MainWindowViewModel
{
    get
    {
        return objectContainer.Resolve<MainWindowViewModel>();
    }
}

public FirstViewModel MyFirstViewModel 
{
    get
    {
        return objectContainer.Resolve<FirstViewModel>();
    }
}

public SecondViewModel MySecondViewModel 
{
    get
    {
        return objectContainer.Resolve<SecondViewModel>();
    }
}
TMan
  • 4,044
  • 18
  • 63
  • 117
  • 5
    Unit test should target `ViewModel class (business logic)` and not View. If in your ViewModel class you are initializing a View, there is terribly something wrong in design. – Rohit Vats Dec 24 '13 at 17:22
  • Yea but this view model is more of a container view model that dynamically creates/sets views (IView)'s and uses them within a content control in xaml – TMan Dec 24 '13 at 17:30
  • I do see your point though and I will try to see if I can opt to set my views all in xaml instead of the view – TMan Dec 24 '13 at 17:32
  • Also I like setting my views in the view model where applicable bc its the closest thing i can get to unit test the actual view. Now I know what your going to say "WHY would I even attempt to test my views?" The higher the test coverage the better quality the app is. All there is to it. – TMan Dec 24 '13 at 17:38
  • 4
    That's completely opinion based. If you like that way, it's your call. I won't comment on that. Merry Christmas..!! – Rohit Vats Dec 24 '13 at 17:40
  • Could you provide ViewModelLocator code? If you implement it properly there are a few ways to do unit test. – Ekk Dec 26 '13 at 08:29
  • I updated to show my view model locator code – TMan Dec 30 '13 at 14:54
  • @TMan, could you please post the implementation of the unit-test? – Sergey Vyacheslavovich Brunov May 02 '15 at 06:42

1 Answers1

1

This is a bit late, but maybe useful. Instead of resolving objectContainer in the constructor, do it through the property:

//note this is a lazy getter, i.e. will be resolved when needed on the first call
private IContainer ObjectContainer
{
   get
   {
       if(objectContainer == null)
           objectContainer = App.ObjectContainer;
       return objectContainer:
   }
}

Then use the property through your code, not the field. Also when I am concerned about someone else using the field that I want to enforce through the property usage, I would rename it to something that would not easily be recognizable in the IntelliSence (zREgdnlksfObjectContainer for example:) ) Note the property is private, so nothing really changes. You can make the property internal and mark your lib to be visible to your unit test, so that in the unit test you can Mock it to WhenCalled() return/resolve IContainer.

denis morozov
  • 6,236
  • 3
  • 30
  • 45