Colin Bacon, web developer.

Testing property changed events with MvvmCross

Testing property changed events with MvvmCross

If you're using MvvmCross to handle property changed events you might find that executing a valid unit test fails because the property changed event doesn't fire.

Why won't you pass?

MvxNotifyPropertyChanged handles property changed events in MvvmCross. It's an abstract class and is implemented on the view model so that property changed events can be raised and handled. For example:

public class BaconViewModel : MvxNotifyPropertyChanged
{
    private bool _isAwesome;    

    public BaconViewModel()
    {
        PropertyChanged += LocalPropertyChanged;
    }

    public string Variety { get; set; }

    public bool IsAwesome 
    {
        get 
        {
            return _isAwesome;
        }

        set 
        { 
            _isAwesome = value;
            RaisePropertyChanged(() => IsAwesome);
        }
    }

    private void LocalPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(e.PropertyName == "IsAwesome")
        {
            Variety = IsAwesome ? "Bacon" : "Facon";
        }
    }
}

Testing, Testing

Let's write a test for this.

[TestMethod]
public void IsAwesome_WhenTrue_SetsTypeToBacon()
{
    // Arrange
    var sut = new BaconViewModel();

    // Act
    sut.IsAwesome = true;

    // Assert
    Assert.IsTrue(sut.Variety == "Bacon");
}

You would expect this to pass, but it doesn't. The property changed event is never raised and so Variety is not set.

MvvmCross Marshalling

By default MvvmCross marshals RaisePropertyChanged calls onto the UI thread. In our unit test this call will never be made. However, if you want to disable the marshalling on an object, you can call ShouldAlwaysRaiseInpcOnUserInterfaceThread(false).

Example:

[TestMethod]
public void IsAwesome_WhenTrue_SetsVarietyToBacon()
{
    // Arrange
    var sut = new BaconViewModel();
    sut.ShouldAlwaysRaiseInpcOnUserInterfaceThread(false);

    // Act
    sut.IsAwesome = true;

    // Assert
    Assert.IsTrue(sut.Variety == "Bacon");
}

Now our unit test passes!