3

I am building a Prism 4 app, and I use the ServiceLocator to instantiate objects. The ServiceLocator is causing unit testing problems, and that leads me to wonder whether I should go back to injecting the IoC container into each class that needs it.

Here is an example of the problem from a repository base class:

protected RepositoryBase(string filePath, Type contextType, string edmName)
{
    m_Logger = ServiceLocator.Current.GetInstance<ILoggerFacade>();

    // Log invocation
    m_Logger.Log("RepositoryBase constructor invoked.", Category.Info, Priority.None);

    // Create object context
    ...

    // Log completion
    m_Logger.Log("RepositoryBase constructor completed.", Category.Info, Priority.None);
}

I am creating unit tests for my repository, and I have discovered that the ServiceLocator doesn't work, presumably because Prism isn't initialized for my test.

Can the ServiceLocator be used in a testing context? Sould I drop it and go back to injecting the IoC container directly? Since service locators seem to be falling out of favor generally, would I be better off not using it? Thanks for your help.

David Veeneman
  • 18,912
  • 32
  • 122
  • 187
  • It turns out I had stumbled into an anti-pattern--actually a couple of them. Injecting containers is probably not a good idea. Se this thread: http://stackoverflow.com/questions/5761167/mocking-an-ioc-container – David Veeneman Apr 29 '11 at 17:33

2 Answers2

4

You need to create a mock IServiceLocator, initialize the service locator with your mock provider in your test.

That should do it.

Damian Schenkelman
  • 3,505
  • 1
  • 15
  • 19
0

I was able to unit test a Prism + Silverlight 4 application successfully and can't think of any reason why you shouldn't be able to use ServiceLocator from your unit tests. You will need to ensure that prism is initialized correctly in the [TestInitialize] part of your code though.

NateTheGreat
  • 2,295
  • 13
  • 9
  • Thanks--how would I go about initializing Prism in [TestInitialize]? – David Veeneman Apr 21 '11 at 19:43
  • I think I've got it--use the same initialization code I would use in App.xaml. Instantiate a bootstrapper and run it. – David Veeneman Apr 21 '11 at 19:58
  • That's correct, although you shouldn't need to call `Run()` on the bootstrapper, as that will create your shell and set up the regions and other visual components (not good for unit tests). If you crack open the code for the base bootstrappers (such as MefBootstrapper.cs) and look at the Run() method, you can see the steps it follows to get the container and then the ServiceLocator set up. – NateTheGreat Apr 21 '11 at 20:25
  • Initializing the Service locator looks like more trouble that it's worth--I think I'm going back to my old Prism practive of injecting the container. – David Veeneman Apr 21 '11 at 21:53