In this post I’ll create the simplest application that covers the basics of MVVM in the context of unit testing. The application does just click counting - it’s the simplest app that I could think of that can be used to demonstrate view models, INotifyPropertyChanged, data binding, commands and unit testing. We will NOT be using any MVVM frameworks.

The destination: Click Counting App

This is what we aim for:

Click Counting App

The Model

This application is so barebones that the model if we choose to implement it would have just one property: ClickCount and no logic inside it. This property is better suited for the view model - even the click keyword suggests that.

The View Model

In order to support data binding between the view and the view model we’re going to implement the INotifyPropertyChanged interface.

But first: what the heck is data binding and why do we need it? Data binding is simply a way to automatically synchronize the changes between the view and the view model. So, if one changes, then the other will change as well.

This “automatic” behaviour is done using events (which are in turn an implementation of the Observer design pattern). That event is called PropertyChanged and it is used by the view to subscribe to changes in the view model when the DataContext property is set on the view (in our case MainWindow.xaml).

In order for the view to know that you have the PropertyChanged event so it can subscribe to it you have to implement the INotifyPropertyChanged interface. Here’s how to do it:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace ClickCountingApp
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Here’s what Microsoft has to say regarding the naming conventions:

Typically, to raise an event, you add a method that is marked as protected and virtual. Name this method OnEventName; for example, OnDataReceived. The method should take one parameter that specifies an event data object. You provide this method to enable derived classes to override the logic for raising the event. A derived class should always call the OnEventName method of the base class to ensure that registered delegates receive the event.

Source: Official Microsoft Documentation for Events in the .NET Framework

In our case, we didn’t respect the convention fully: we needed to also provide the sender and the event argument instead of the changed property name. We did it like this because this is the most common/simplest approach in this case. This is the only place (that I know of) where the convention is not respected.

Well, now we have the event in place, but we also need the property that will use it. We just need to declare the property and be careful to call OnPropertyChanged in the set.

private int clickCount;
public int ClickCount
{
    get { return clickCount; }
    set
    {
        clickCount = value;
        OnPropertyChanged();
    }
}

Normally, we would have to specify the name of the changed property (like this: OnPropertyChanged("ClickCount")), but since we’re using the CallerMemberName, this will be automatically filled in based on the member that calls the method (in our case the ClickCount property).

The command

The next step is to implement the actual click counting behavior. For this, we’re going to use commands. In WPF, commands have to implement the ICommand interface, so let’s do this:

using System;
using System.Windows.Input;

namespace ClickCountingApp
{
    public class IncreaseCountCommand : ICommand
    {
        private readonly MainViewModel viewModel;

        public IncreaseCountCommand(MainViewModel viewModel)
        {
            this.viewModel = viewModel;
        }

        public void Execute(object parameter)
        {
            viewModel.ClickCount++;
        }

        public event EventHandler CanExecuteChanged;
        public bool CanExecute(object parameter) => true;
    }
}

In this post, to keep things simple, we’re going to ignore the CanExecuteChanged event and the CanExecute method will just return true - we will always allow the execution of the command.

The IncreaseCountCommand has to know about the view model in order to increase the ClickCount so we’re going to provide it as a constructor argument.

The final step is to implement the Execute method which in our case will just increase the ClickCount from the view model.

Besides defining the command, we also need to add a property in the view model and initialize it in the constructor:

public ICommand IncreaseCount { get; set; }

public MainViewModel()
{
    IncreaseCount = new IncreaseCountCommand(this);
}

The view model tests

We’re going to use the default unit testing framework available. Normally I’d use NUnit, but to keep the example as simple as possible I’ll just use the default since it’s good enough. Here are the tests:

using ClickCountingApp;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Tests
{
    [TestClass]
    public class MainViewModelTests
    {
        [TestMethod]
        public void ClickCountIsZeroByDefault()
        {
            var viewModel = new MainViewModel();

            Assert.AreEqual(0, viewModel.ClickCount);
        }

        [TestMethod]
        public void ClickCountIsIncreasedWhenCommandIsExecuted()
        {
            var viewModel = new MainViewModel();

            viewModel.IncreaseCount.Execute("ignored");

            Assert.AreEqual(1, viewModel.ClickCount);
        }
    }
}

You should pay attention especially to the second test since it shows how to test the command. In this case we don’t have any parameter for the command, but I chose to use the "ignored" string instead of null to make it very clear that it’s not used. The test is following the Arrange, Act, Assert pattern which allows clear separation between the steps.

The View

This can be created directly using the visual designer by creating 2 rows in the default Grid and drag and dropping a TextBlock and a Button on each row. Here’s the full XAML code:

<Window x:Class="ClickCountingApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ClickCountingApp"
        mc:Ignorable="d"
        Title="Click Counting App"
        Width="400"
        Height="300">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0"
                   Text="{Binding ClickCount}"
                   FontWeight="Bold"
                   FontSize="50"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center" />
        <Button Grid.Row="1"
                Content="Increase Count"
                Command="{Binding IncreaseCount}" />
    </Grid>
</Window>

You should pay attention how the view model is associated with the view by using the DataContext property of the Window:

<Window.DataContext>
    <local:MainViewModel />
</Window.DataContext>

You should also pay attention how we access the view model properties from the view using data binding:

<TextBlock Text="{Binding ClickCount}" />
<Button Command="{Binding IncreaseCount}" />

Source Code

The full source code is available on GitHub. You can clone the repo and try it locally.