8

Disclaimer: Prism Novice. I'm reading up furiously to make up for lost time though :)

Context: I need to write automated acceptance tests for a WPF application built using Prism.

Issues: I find that it is convoluted trying to compose the backing ViewModels and everything that they need without the UI.

I may be wrong here... Prism allows you to mark up the shell with named placeholders (regions). Different modules (isolated units) register their Views with the corresponding RegionNames. The Views also have a dependency on the ViewModel (ctor injection) which is injected via MEF/Unity.

  1. Showing the view
  2. triggers creation of child views (regionName => View registry)
  3. triggers creation of child view models (Mef ctor injection).

Composing the app is thus delegated to Prism (or more importantly the View). This seems like a view-first approach. This throws a spanner in the works for starting up the app without the UI ; testing with the UI is a pain.

What I am looking for is a presenter first approach, which composes the entire object (ViewModel and dependencies) graph without the UI.

var viewModel = Someone.ComposeAndGet<ShellViewModel>();

Is it possible with Prism4 by writing apps differently OR is it not supported ?

[Update : Dec 2011]
http://compositewpf.codeplex.com/discussions/283065
Posted on the prism forums to get shed some more light; seems like it is not possible. The recommendation is to use UI tests for acceptance tests. Prism composes UIs ; thereby has a crucial dependency on views.

Gishu
  • 134,492
  • 47
  • 225
  • 308
  • Good question - I have had this sinking feeling about PRISM and MVVM ever since we implemented it in our solution. We are now running into the test issues you describe. It seems that MVVM has been retro-fitted into PRISM and the two don't play well. Navigation is an ideal example - to test without the View we need to hold the navigation state purely in the view model, but PRISM hard wires us to the view by doing navigation plumbing through Regions. Setting up RegionManagers and Regions in the ViewModel and then binding to them from the View could be the way - but alas it doesn't seem to work – James Close Aug 24 '12 at 15:46
  • @JamesClose - yes that is one of the ways that the Prism team (due to our support agreement with MS) proposed as potential avenues. Regions can hold ViewModels as well + ViewModels can contain the Regions. However it isn't supported by MS. You can hack something up and get it to work.. however it is not something that MS would test for explicitly or preserve behavior with future releases. They said they have been hearing similar requests but it's not on top of their next-feature queue. Another gap w.r.t. Prism docs is the definition of view-model first = view injection from the VM – Gishu Aug 25 '12 at 02:53

2 Answers2

3

I like the Prism framework, however I rarely use Prism's Regions because I feel it forces me into a View-First approach.

I dislike using View-First because I feel it eliminates some of the advantages of using the MVVM design pattern, such as keeping your layers separate, and unit testing. If your Views are responsible for creating your ViewModels, then to test your ViewModels you either need to create the Views to create the ViewModels, or you need to manually create your ViewModels.

I also feel that an ideal MVVM application should allow you to run the application with any UI, even command-line, and by using Regions I am limiting my ViewModels to a Prism interface.

I'll still use Prism's regions on occasion, but usually only for the startup page (e.g. TitleBarRegion, MenuRegion, ContentRegion)

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Precisely my sentiments. But then if I rule out regions, does Prism help at all? How would you do view composition ? There is hardly any documentation related to this topic on MSDN.. or have I missed a link? – Gishu Dec 05 '11 at 17:30
  • @Gishu I love using Prism's `EventAggregator`, `NotificationObject`, and `DelegateCommand`. I have used MEF injection a bit, although I wouldn't call myself an expert with it. The only part I really don't like using is the Regions. – Rachel Dec 05 '11 at 17:42
  • @Gishu Usually I handle navigation through an `ApplicationViewModel`, which contains available and current pages (along with things like the Current User, and Error Messages). I wrote an example of it here if you're interested: http://rachel53461.wordpress.com/2011/07/17/navigation-with-mvvm/ I actually am in the process of rewriting that post to be a little clearer, and to include a working code-sample, and am hoping to update it next weekend (providing Christmas shopping doesn't get in the way) – Rachel Dec 05 '11 at 17:43
  • Perhaps I did something wrong, but I used Prism and it's regions with a ViewModel-First approach and I didn't see any disadvantages. – PVitt Dec 06 '11 at 08:39
  • I disagree, prism regions enable you to do really neat stuff, I inject my views into a region contained in an AvalonDock.DocumentPane and with a little RegionAdater magic it puts the view in a scrollviewer, then in a new tab and then it pushes it in the DocumentPane. Works like a charm and feels clean. – Louis Kottmann Dec 07 '11 at 16:53
  • @Baboon I suppose it's a matter of preference. Personally I prefer to bind my current View to a ViewModel's property, then set that ViewModel's property to whatever ViewModel is supposed to be displayed in the View and let WPF's DataTemplates take care of how to draw items. – Rachel Dec 07 '11 at 17:50
  • @Rachel I don't understand how using prism's regions would prevent me from doing that. I use MVVM extensively. – Louis Kottmann Dec 07 '11 at 17:56
  • @Baboon It doesn't, but I feel that Prism's regions prevent me from running my application with a different (or even non-existent, such as test cases) UI because the Regions control what gets displayed/created, and when, not the ViewModels. – Rachel Dec 07 '11 at 17:58
  • @Rachel yes, I've been thinking about this question and I didn't find a way (yet?) to easily achieve acceptance test. Maybe we can make it a feature request to MS' P&P team. – Louis Kottmann Dec 07 '11 at 18:00
  • @Rachel - I'm kind of surprised with the paucity of answers. How is everyone writing acceptance tests for apps built on PRISMv4 - through-the-UI Tests ? I'm still 50% through the dev-guidance... so refraining from launching a full blown rant :) – Gishu Dec 08 '11 at 08:46
  • @Baboon, PVitt - since testability is a primary (if not THE) reason for the MVVM, doesn't it seem natural that it should extend to the system level as well. MVVM is supposed to make both unit AND acceptance tests easier to write and without any dependencies on the UI. Does prism provide any support for presenter first? Do I have to handle view-composition myself ala plain vanilla WPF apps ? – Gishu Dec 08 '11 at 09:04
1

I'm not entirely sure i understand the question, however to Unit test a prism app:

You can use the ServiceLocator to retrieve ViewModels:

MainViewModel mainVM = ServiceLocator.Current.GetInstance<MainViewModel>(); //That will "compose and get"

And then you can unit test it as you please.

That said, Prism, and MVVM in general, delegates most of the responsibilities to the VM. The View is just a representation of the data, it holds no logic.
The VM holds the data/logic and makes the changes to it, without ever knowing which view it is actually bound to.

Hope this helps =)

Louis Kottmann
  • 16,268
  • 4
  • 64
  • 88
  • 1
    I'm looking at writing acceptance tests. That means if the Shell contains 2 regions (say a tree and a list ala Windows Explorer), then showing the view is what triggers creation of the TreeVM and the ListVM. If I don't show the parent View, the view-models are never created. In short, I want to trigger the composition of the ViewModel graph without bringing up the UI. – Gishu Dec 05 '11 at 09:58
  • So you want to know when the views/viewmodels are created? The ServiceLocator I talk about does not create any UI if you just ask for the VM. – Louis Kottmann Dec 05 '11 at 10:00
  • When I run the app, showing the View triggers creation of the child View and ViewModels recursively and everything works. In my tests, since I won't bring up the Parent View, the child ViewModels won't get created unless I write specific code for that (which would be a maintenance hassle - e.g. someone adds/removes a region). In the example above, I'd want a method that creates ShellViewModel and then triggers creation of TreeVM and ListVM *without the UI*. Basically I want to compose everything below the UI, peel off the UI so to speak. – Gishu Dec 05 '11 at 10:05
  • The problem you're facing is that in MVVM/Prism, the views can accept several different viewmodels, and viewmodels don't know their views. This achieves loose coupling. At the same time, this also means that doing what you want is likely to involve reflection... – Louis Kottmann Dec 05 '11 at 10:08
  • It doesn't seem like it's that simple; Prism does a lot of stuff behind the scenes e.g. if the ActiveView changes from View1 to View2, it may dump all objects with View1 as the root of the graph and bring a new object graph into memory. Now the Shell may raise events that will be handled by View2VM. If I don't have the UI, I basically have to simulate all this via code - which is infeasible. e.g. If I forget to write code to instantiate View2VM and it minions at the right time, the test might report a false failure. – Gishu Dec 05 '11 at 10:51