Catel is a brand new framework (or enterprise library, just use whatever you like) with data handling, diagnostics, logging, WPF controls, and an MVVM Framework. So, Catel is more than "just" another MVVM Framework or some nice Extension Methods that can be used. It's more like a library that you want to include in all the (WPF) applications you are going to develop in the near future.

1. Introduction

Welcome to part 4 of the articles series about Catel. This article explains how to write unit tests for MVVM using Catel.

If you haven’t read the previous article(s) of Catel yet, it is recommended that you do. They are numbered so finding them shouldn’t be too hard.

I must admit that some parts of this article are greatly inspired by the article about unit testing in Cinch by Sacha Barber, which actually led me to writing an article about unit testing in Catel at all.

If you are wondering why you should even write unit tests, you should also wonder why you aren’t still living in a cage and writing stuff on the walls. Writing unit tests makes sure that you don’t break existing functionality in an application when making changes. This lowers the cost of QA (since you don’t need a technical tester executing regression tests all the time). I don’t say that a tester isn’t needed; my opinion is that at least someone else besides the developer should take a human look at the software before it is even released. If you are still not convinced why you should write unit tests, please go back to your cave and stop reading this article for the sake of your own pleasure.

During this article, you will notice how easy it is to write unit tests for your View Models. It might even be fun, although I doubt that there are a lot of developers that find writing unit tests fun. At the end of this article, we will write unit tests for a “real-world” application so this article isn’t too abstract to read.

This article does not cover the basics of unit testing. It assumes that you already know what unit tests are, and how to write them. This article is specifically written to explain how View Models of the MVVM pattern can be unit tested, especially with the use of Catel.

2. Testing Commands

Thanks to commands (which implement the ICommand interface), testing View Models and UI logic has never been so easy. Now commands can be invoked programmatically without having to automate the UI; it is very simple to reproduce a button click during a unit test.

When testing commands, it is very important to test the state as well. The command implementation of Catel has a CanExecute and an Execute method which can be invoked manually. Therefore, it is very easy to test a command. The code below shows a test that checks whether the Remove command can be executed. At first, the command cannot be executed because there is no selected person. After the selected person is set, the command should be able to execute:

3. Testing Services

Catel uses several services that are exposed to the ViewModelBase class. These services are registered by interface, so can be different for each View Model. This chapter explains how the services can be used during unit tests.

By default, the ViewModelBase registers the right service implementations (either the WPF or Silverlight specific implementations). However, during unit tests, you won’t be there to click the confirmation buttons in a message box. Therefore, Catel also offers unit test implementations of all the services.

3.1. IoC containers

Catel uses Unity to implement IoC containers. IoC containers make it possible to change dependencies at runtime by configuration without actually having to change the code or even recompiling. To enable the unit test implementations for a unit test project, we have to create an App.config file (if it doesn’t already exist) and use the following content. Note that if you already have a configuration file, do not completely overwrite the configuration file, but merge them.

The code above maps all the known interfaces to the test implementations of the services. Unity will make sure that the right services are injected into the View Models. As soon as a View Model instance is created in the test project (don’t forget to initialize it), you can retrieve the test implementation of the service like this:

3.2. IMessageService

This service is almost completely empty in the test implementation since most message boxes just contain the OK button, which can be ignored during unit tests. The only methods that actually return a value are the methods that have a return value.

The implementation adds a new property ExpectedResults. This way, a unit test can set an expected result so the service will know what to return on the next call. If there is no queue available, an exception will be thrown since the unit test is not correctly written. Below is the most important part of the service implementation:

Now we have discussed the implementation of the service, let’s take a look at how we can use it:

Test.MessageService service =
(Test.MessageService)GetService<IMessageService>();
// Queue the next expected result
service.ExpectedResults.Add(MessageResult.Yes);

3.3. IOpenFileService and ISaveFileService

The IOpenFileService and ISaveFileService implementations are the same; therefore they are handled in the same paragraph.

The implementation adds a new property ExpectedResults. This way, a unit test can set an expected result so the service will know what to return on the next call. If there is no queue available, an exception will be thrown since the unit test is not correctly written. Below is the most important part of the service implementation:

Instead of showing PleaseWaitWindow and let the window handle the work delegate, the service itself executes the work delegate and then returns.

3.5. IProcessService

The implementation adds a new property ExpectedResults. This way, a unit test can set an expected result so the service will know what to return on the next call. If there is no queue available, an exception will be thrown since the unit test is not correctly written.

However, unlike the other services, this service will only return a result code and invoke the callback in case the process is started successfully. Therefore, an intermediate class ProcessServiceTestResult, which is defined below, is required:

///<summary>/// Class representing the process result.
///</summary>publicclass ProcessServiceTestResult
{
#region Constructor & destructor
///<summary>/// Initializes a new instance of the
///<seecref="ProcessServiceTestResult"/> class,
/// with <c>0</c> as default process result code.
///</summary>///<paramname="result">if set to <c>true</c>,
/// the process will succeed during the test.</param>public ProcessServiceTestResult(bool result)
: this(result, 0) { }
///<summary>/// Initializes a new instance of the
///<seecref="ProcessServiceTestResult"/> class.
///</summary>///<paramname="result">if set to <c>true</c>,
/// the process will succeed during the test.</param>///<paramname="processResultCode">The process result
/// code to return in case of a callback.</param>public ProcessServiceTestResult(bool result, int processResultCode)
{
Result = result;
ProcessResultCode = processResultCode;
}
#endregion#region Properties
///<summary>/// Gets or sets a value indicating whether the process
/// should be returned as successfull when running the process.
///</summary>///<value><c>true</c> if the process should be returned
/// as successfull; otherwise, <c>false</c>.</value>publicbool Result { get; privateset; }
///<summary>/// Gets or sets the process result code.
///</summary>///<value>The process result code.</value>publicint ProcessResultCode { get; privateset; }
#endregion
}

Now that we have discussed the implementation of the service, let’s take a look at how we can use it:

Test.ProcessService service = (Test.ProcessService)GetService<IProcessService>();
// Queue the next expected result (next StartProcess will
// succeed to run app, 5 will be returned as exit code)
service.ExpectedResults.Add(new ProcessServiceTestResult(true, 5));

3.6. IUIVisualizerService

IUIVisualizerService is the most complex of all, if you can even call it complex. The reason for this is that a separate expected results queue is available for the windows that are shown as a dialog or as a regular window. Below is the code that shows how Show is implemented, but ShowDialog is implemented in the same way:

4. Example Project

Now that you have learned all the things you need to know about unit testing in Catel, it’s time to bring it into practice. As an example, a person application is created. It’s a very simple application which does nothing more than adding, modifying, and removing persons in a list. But, as simple as the application might seem, it contains most aspects that need to be tested when using MVVM.

In the solution of Catel, we have created two new projects, starting with the name Catel.Articles.04 - Unit testing. The first one is the actual application that is written for this example. The second one is the test project containing unit tests.

4.1. Functionality

The application is fairly simple, and should speak for itself. However, here are some screenshots to give you an idea of what the application is capable of doing.

The main window of the application consists of an items control with all the persons listed underneath each other. At the right are manipulation buttons which should be fairly easy to understand thanks to the images.

Note that it is possible to double-click a person item to edit it. This is implemented thanks to the EventToCommand trigger of Catel.

When the Add or Edit button is clicked, the detail window will popup containing some fields to edit the values.

As said before, the application is very simple and does nothing useful, but that’s actually the point to keep it as simple as possible. You will probably recognize these kinds of scenarios, and can map them back to your own problems in your own applications.

4.2. Setting up IoC

In the unit test project, we don’t want to use the same services as in real life. For example, why would one want to see a message box during a unit test? Therefore, Catel offers unit test implementations of all View Model services provided by Catel. The actual behavior of the services is described earlier in this article, so we are going to use them, not explain them.

To make sure that the unit test uses the right services, we are going to configure this via the application configuration of the unit test project.

As you can see, we map the interfaces to the test implementations of the services. The Unity framework will take care that the right instance of the services is used during the unit tests.

4.3. Testing Models

Let’s start with the easy one. We have only one Model, and want to test it on a few things, such as validation. We also have an automatic property called FullName, which is just a concatenation of all the known names (first, middle, and last).

4.4. Testing View Models

Now that we know that our Model is fine (which is very important, the source data must be correct), we can continue with writing unit tests for the View Models. In this article, I will only cover the MainWindowViewModel class. The PersonViewModel class is so straightforward that it is a nice exercise for you to complete.

We first start with testing the initialization of the View Model. During initialization, we expect the View Model to initialize one person, namely me. Below is the unit test:

The initialization seems to work just great. Let’s focus on the commands. First, we test the Add command. There are two situations we need to test, because the user can either choose OK or Cancel in our modal dialog. If the user clicks Cancel, we don’t want to add the new person:

Until now, it has been fairly easy to write the unit tests, right? We only had to instantiate and initialize a View Model, then set the expected results of the services and check the results. The Remove command is just as simple, but now shows how to use the IMessageService test implementation.

5. Conclusion

This article first explained the unit testing capabilities of Catel and how to use them. Finally, we have written a complete sample application including unit tests for both Models and View Models. I hope that this article shows you how easy it is to write unit tests, and that you should definitely start writing tests for your software.

It also shows a very strong point of the MVVM pattern. If you don’t follow a pattern that creates loosely coupled systems, you will soon notice that it is very hard, if not impossible, to write unit tests for your software and UI logic.

Share

About the Author

I am Geert van Horrik, and I have studied Computer Science in the Netherlands.

I love to write software using .NET (especially the combination of WPF and C#). I am also the lead developer of Catel, an open-source application development framework for WPF, Silverlight, WP7 and WinRT with the focus on MVVM.

I have my own company since January 1st 2007, called CatenaLogic. This company develops commercial and non-commercial software.

Comments and Discussions

Hi,
I am following some of the tests in this article but I am getting an exception when I try to set up the uiVisualizerService in a test method like AddPerson_Confirmed. I am getting an 'Unable to cast object of type 'Catel.MVVM.Services.UIVisualizerService' to type 'Catel.MVVM.Services.Test.UIVisualizerService'.

I have installed the NUGet UnityConfiguration package into my test project but this did not solve the problem.

I am using VS2012 and the downloaded source gives me errors because it cannot find the Unity dlls since the lib folder is not in the download. There are a lot of unnecessary projects in the solution that make it hard to focus on the stuff in this article and the downloaded zip does not contain the lib folder or NuGet package restore. I cannot build this solution.

I have followed the example and included the app.config. I notice in the CodePlex Catel.Test project that there is a Catel ioc section - has the method of swapping services changed since this article was written.

This is a great series, but I can't help but feel uncomfortable at the amount of work that is being done inside some of your tests. When you are testing your validation, you have a wide variety of asserts going on in there, which can lead to difficult to track issues. It's generally better to just test one thing in a test.

I always like to assert the pre-situation, perform an action and check the
post-situation.

That's one way of doing it, I suppose, but tests should really be atomic so, in general, there should be no need for the pre-assert. But, going back to your Model validation method, you aren't just testing one post condition. In that method, you're testing several post conditions. These really should be individual tests.

"I must admit that some parts of this article are greatly inspired by the article about unit testing in Cinch by Sacha Barber, which actually led me to writing an article about unit testing in Catel at all."

That's a good thing, people should think about Unit testing a lot more, the amount of times I have seen people writing MVVM code that is completely untestable, which to my mind is the main point (apart from SOC) of the pattern.

Oh by the way the queued expected results is one of my better ideas I feel. Mocks could not do a better job than that, the queue idea was a good one I feel, so nice to see someone picking up on that. I think that passed a lot of people by.

I think Catel looks like a really nice framework.

Sacha Barber

Microsoft Visual C# MVP 2008-2011

Codeproject MVP 2008-2011

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue