Unit Testing Custom Xamarin.Forms Controls

When using Xamarin.Forms, the conventional wisdom is that you write unit tests around the ViewModel, but not the View. This approach works well for most cases with MVVM, but if you’re developing custom controls, it’s likely not sufficient. In this post, I’m going to dive into a bit of what it takes to successfully write unit tests around custom Xamarin.Froms controls.

Do You Really Need to Unit Test Your Views?

Before I jump into writing View unit tests, it’s probably worth talking about whether this is really necessary. Most advice you’ll find says not to write tests on the View. I think in a lot of cases, that’s pretty solid advice; the ViewModel should usually be in charge of the logic.

But if you are developing controls that will be reused throughout your app and they have reason to contain real logic, I think there is a strong case for unit testing them. Typically, these are controls with multiple bound properties that need to manage some state internally.

Basic Setup

You probably started your solution with a unit test project. If not, you’ll add a new project for unit tests. Make sure to add the shared project as a reference in your unit tests. You’ll also want a testing framework. I’ve been using NUnit, which is used by default for new Xamarin.Forms solutions.

If you plan on mocking out any functionality, you might want to pull in Moq while you’re at it, though I won’t go over its use here. Check out the “Intro to Mocking with Moq” if you’re interested in learning about it.

Handling Subcontrols

Now, you’ll likely want to make some assertions on elements within your custom control. Maybe you want to check the Text of a Label or see if a Button is enabled. To do this, you should give them a name, using the x:Name property.

The only issue here is that these subcontrols will be private, so you can’t access them from your tests. The best way I’ve found to deal with this is to add an internal getter for the private controls and expose internal properties to your test. The getter can be as simple as:


// assuming myLabel is the name of the Label
internal Label MyLabel => myLabel;

To expose internal properties to your test project, you can create a “Properties” directory in your shared project. Then create an AssemblyInfo.cs file in it that looks like this:


using System.Runtime.CompilerServices;

// Use your test project's name
[assembly: InternalsVisibleTo("myproject.UITests")] 

But Wait! There’s More!

There are two types of exceptions that I started running into pretty quickly:

  • Xamarin.Forms.Xaml.XamlParseException ... StaticResource not found for key ...
  • System.InvalidOperationException : You MUST call Xamarin.Forms.Init(); prior to using it.

To take care of both of these problems, I’ve found that I need to:

  • Mock out Xamarin.Forms using Xamarin.Forms.Mock
  • Set the static Application.Current to an instance of the App

I like to use the following base class for all my View unit tests:


namespace viewunittester.UITests.Tests
{
  public class ViewUnitTestBase
  {
    [SetUp]
    public void SetUp()
    {
      MockForms.Init();

       Application.Current = new App();
    }

    [TearDown]
    public void TearDown()
    {
      Application.Current = null;
    }
  }
}

Putting It All Together

Okay, so here’s what a sample test could look like:


[Test]
public void ()
{
  var control = new MyView();

  // Assuming StringToShow is a bindable property
  control.StringToShow = "Hello world";

  Assert.AreEqual("Hello world", control.MyLabel.Text);
}

Try it out, and see what you think!