XAMVVM-02 TDD UnitTesting with Xamarin.Forms!

Thinking of how to adopt Testing practices into your Xamarin.Forms project, in this world of test driven software development? 😉 You’re about to find out!

Yes, you can easily incorporate UnitTest cases into your Xamarin.Forms project just like any other .NET solution, and there’s plenty of ways to do with several test frameworks.

As for the sake of clarity let me start off with a bit of basics…

Why UnitTesting?

So that we could write better software, with minimum failure rate. Specially for the continuous development of the software, making sure today’s code logic change doesn’t break any other elements of the application the next day, to simply put.

UnitTesting is a great approach for Test Driven Development based software building, where we test our code from the smallest units we could break into, making sure top to bottom all the bits are executing as expected! 😉

Follow a pattern…

It’s best to keep your UnitTest cases organised and categorised, as it could get messy when your Application grows as well as your test code base. You can organise your test cases according to a certain pattern, either based on your Application Pages or Flows.

Using Page based pattern for organising our test cases, allows us to write the test cases as they originates from each Page context itself. Further more on the base of behavior and functionalities available in each page in the application, as an example Home Page, Shopping Cart Page, Payment Page, and etc…

You could also use a Flow based pattern for your test cases, where you write test cases accordingly each individual feature flow of the application, as an example Login Flow, Order Flow, Payment Flow, and etc…

The choice is up to your requirement and the nature and complexity of your app. Although in my opinion page based approach could be easy to manage the test cases in long run.

Xamarin.Forms and UnitTesting!

Basically we could use any .NET Testing framework to test our Xamarin.Forms projects such as following.

  • MsTest
  • NUnit
  • xUnit, etc…

There are mainly two approaches we could take for UnitTesting our Xamarin.Forms project…

– ViewModel instances testing: This is about creating instances of the ViewModels of the app inside our UnitTest environment and testing each execution flow.

– Runtime Mocked testing: Here we’re creating a mocked app run time using a third party library inside our UnitTest environment and testing each execution flow.

ViewModel based testing, is a very limited form of testing hence there’s no way to perform testing on Navigation and UI Interactions flows. Although this is very easy to implement, it is not very effective, since with Xamarin.Forms applications we’re dealing with user interactions and all. Runtime Mocked testing is actually a much better way, hence we get to go through the actual application UI flow for each our test cases. So let’s do that! 😉

Xamarin.Forms Runtime Mocked UnitTesting!

Like I said above, this is the most effective since it not only saves a lot of development time, but also beneficial for TDD practices for accelerating development.

So we need to mock the Xamarin.Forms runtime without actually launch the app in an emulator or a device, which is going to be done using this awesome library, Xamarin.Forms.Mocks! Allowing us to create an actual instance of the app in memory, mocking the whole Xamarin.Forms run-time, allowing us to navigate through the app as if we’ve actually launched the app.

How to?

First thing we need to create a new UnitTest project in our Xamarin.Forms solution. Then add a reference of our Xamarin.Forms .Net Standard project to it, so that we can instantiate the app and add references from it into our test project. Next we have to add Xamarin.Forms.Mocks, nuget to the test project to emulate the Xamarin.Forms run-time. 😀

Finally, you can straight up create an instance of App class and access your Xamarin.Forms project’s objects in runtime!

But if you’re using a 3rd party MVVM framework like Prism, they usually have their own Container registration, which we need to manually handle ourselves in a mocked run-time environment. On the bright side, it also gives us more flexibility of control, since we could register our own mocked services for Test environment, such as a Location Service! whereas we could return a mocked fake location data when we override the LocationService with our own FakeLocationService. 😉

Here we override the default App class in our Test project with necessary container registrations and store it in a singleton static object, so that we can access it anywhere in our test environment. Oh and alongside we’re initiating our Xamarin.Forms Mocks run-time as well!

Now its all ready to go! Pretty straight forward eh! let’s get down to business.. 😉

Hands on time!

So just to showcase this hands-on awesomeness, I’ve prepared a simple Xamarin.Forms project application, where you can create simple notes, attach location data, attach created date time values and store them locally, allowing you to view them at any time in a list of items. Quite a simple text-pad-like app.

I’ve named this project solution as, XFTextpadApp and it uses Prism as the MVVM framework.

As you can see above is a view of the project structure with the complete MVVM set up. Let me also share a bit of showcasing of the app and its features to give a more in depth context.

Here’s a little peek into features of this demo Xamarin.Forms Textpad app running on iOS!

In the Home page you can view the List of Texts you have saved. By clicking on a Text item in the Home page list you can view that Text item in detail in the View Text page. Then once you click the “New Text” Button it will take you to the New Text page where you can create and save new Texts…

In the New Text page you can create new Texts with a Title and Description of your Text and click “Save” button to save it with the Location and Time data attached to it.

Then you will be navigated back to Home page. In the Home page Text list you can delete saved Text by using the context menu as well…

Thanks to Xamarin.Forms we can deploy it directly to iOS, Android, and UWP as well! 😉

Now the App project is ready, we need to add Test project to it.

Let’s begin by adding the Test project to our Xamarin.Forms project, create a new folder in the solution, named as “Tests” and then right click on it -> Add -> Add New Project

Now this is where the choice is absolutely up to you, as to which testing framework to choose from. Just for this demo, I’m gonna use NUnit Test framework, hence I will select NUnit Test Project (.NET Core) template and create our test project…

I will be naming the test project as, XFTextpadApp.NUnitTests making sure to stick to the standard naming practices! You might want to pay some attention to the Project Path there as well, where as to make sure we set the path to be inside the “Tests” folder that we created earlier.

First thing first, add a reference of the host XFTextpadApp .NET standard project into our XFTextpadApp.NUnitTests project. Then we’re going to add our Xamarin.Forms Mocking library, Xamarin.Forms.Mocks.

Just to make sure we write some beautiful test code, let’s add Shouldly nuget as well. This is more of a personal choice 😉 or if you prefer you could use the default assertions of NUnit (NUnit.Framework.Assert), or which ever the test framework you have chosen to set up.

If all went well then you should see the references as above. Now that’s out of the way, next on let’s get into coding!

Create app instance…

You could directly use the existing App class instance inherited from the Xamarin.Forms project within our Test project environment, but in the case of using 3rd party MVVM frameworks, or even when you want to mock some test compatible services, such as a GPS location service!?, then you need to construct your own App instance that’s catered for the Test environment. Which is what we’re going to do in this step.

Something to note here is that, the way you construct your Test App instance is completely dependent on how you have constructed your Xamarin.Forms application, so try to duplicate it as much as possible.

Let’s start by creating the instance of our app for the test environment. This basically means we need to create App class’s instance with all the container registrations set up, similar to what we already have in our App.xaml.cs file. Let create a new class called TestApp in our XFTextpadApp.NUnitTest project root.

public class TestApp : PrismApplication
{
	public TestApp() : this(null) { }

	public TestApp(IPlatformInitializer initializer) : base(initializer) { }

	protected override async void OnInitialized()
	{
		...
		
		await NavigationService.NavigateAsync("NavigationPage/HomePage");
	}

	protected override void RegisterTypes(IContainerRegistry containerRegistry)
	{
		containerRegistry.RegisterForNavigation<HomePage>();
		...

		containerRegistry.GetContainer().RegisterType<HomePageViewModel>(new Unity.Lifetime.ContainerControlledLifetimeManager());
		...
	}
}

Now make sure to register your Pages, ViewModels and Services accordingly. Also notice that how I have set up the default start up navigation in the OnInitialized() method according to Prism.

Next the Hooks…

This is more like the helper class that we’ll be using to set up the necessary hooks for our test run time environment, such as instantiating the App instance object, and initialising MockForms. Here we’re going to keep a public static object of our App instance, which we will be using all across out tests cases. Let’s create a class called TestHooks

public class TestHooks
{
	public static TestApp App { get; private set; }

	[SetUp]
	public static void Setup()
	{
		Xamarin.Forms.Mocks.MockForms.Init();

		App = new TestApp();
	}

	[Test]
	public static void IsAppRunning()
	{
		Assert.NotNull(App);
	}
}

We’re using the [Setup] attribute of the NUnit framework to do the initiation of the App instance before each execution of tests. And we’re also adding a simple test in the same class to make sure the instantiation has happened properly without an issue, as you can see by the method IsAppRunning() which is decorated with the [Test] attribute of NUnit. We’ve made those hooking methods static because we are going to be accessing them in our test cases!

And since we have just added our first Test case, we could try and run it, where as if everything is set up properly, you should see your app instantiating well and our first test case is passing! 😉

And it all passes the test with green! lol 😀

If you can’t get this step to pass successfully, then there’s definitely something wrong with the Test App instance set up, so you might wanna look into the DI Container initialization and all.

Alright, but we’re not done yet!

One base for all…

Then we are one step away from creating our Test cases! 😀 so before that we need to create the Base class for our Test classes that would be containing those Test cases. So let’s create out BaseTest class in the root of the project…

/// <summary>
/// Base class for Test classes
/// </summary>
public class BaseTest
{
    /// <summary>
    /// Instance of the app
    /// </summary>
    public static TestApp App { get; private set; }
 
	[SetUp]
	public void Setup()
	{
		TestHooks.Setup();

		App = TestHooks.App;
	}
     
    ...
}

It’s pretty simple, but its important to abstract a base layer for our test classes to dump all the repetitive test steps to reduce duplication of test code. Here we’re simply retaining the TestApp instance through the TestHooks class we just created before, and that instance will be useful for our Test cases later. 😉

On to the final step!

Creating the Tests…

Now that all is set up and ready to go, let’s create our actual Tests. But first create a “Test” folder in the root of our XFTextpadApp.NUnitTest project.

If everything is well set up until now, then it should look like the above structure.

Let’s add a new class to the Tests folder, but as for the name, you could use anything as you wish according to your preferred naming convention, but I would usually prefer something like “<PageName>Tests”, keeping the Page as the objective for the set of test cases. So let me create HomePageTests class, which will inherit from the BaseTest class.

Next we’re going to create the methods that actually indicates the Test cases, let’s take an example such as,

Scenario:
First time I launch the app
I am Navigated to the Home page
I see an empty list of data
I see a label indicating empty data

We could create the Test case for the above scenario as shown below…

[TestFixture]
public class HomePageTests : BaseTest
{
	/// <summary>
	/// Launching the app for the  first
	/// time and navigating in to Home page
	/// </summary>
	[Test]
	public void AppLaunchingFirstTimeTest()
	{
		// Test steps here
	}
}

As you can see I’ve named our test case method as, AppLaunchingFirstTimeTest, considering the gist of the test scenario that we’re targeting. In fact providing a proper name for your test cases are quite important, hence it makes it easier to read and understand, as well as for future maintenance.

Now Thanks to the Xamarin.Forms.Mock, we’re able to pull objects from Xamarin.Forms UI elements and the DI Container to construct a perfect test case for any given scenario. You can access any Xamarin.Forms elements through the App object as usual to check for any values you require.

So with that in mind, let’s write the Test steps for our test case..

[Test]
public void AppLaunchingFirstTimeTest()
{
	// Is the app running
	App.ShouldNotBeNull();
	
	// Retrieve Navigation Stack
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	
	// Am I in the Home page
	navigationStack.Last().BindingContext.GetType().Name.ShouldBe(nameof(HomePageViewModel));

	// ListView should be empty
	App.Container.Resolve<HomePageViewModel>().TextList.Count.ShouldBe(0);

	// Empty ListView Label Displayed
	App.Container.Resolve<HomePageViewModel>().IsEmptyTextList.ShouldBe(true);
}

Let me explain step by step…

First thing we need to do is to make sure the App is running, so in our Test case, let’s access the TestApp instance in our BastTest class, and use Shoudly’s extension to check for null or not state.

Then we access the Navigation stack through the App’s Navigation object, which we’re going to check for the current active Page, through the BindingContext type as you can see.

Finally we check if the ListView is empty by accessing the TextList collection object inside the Homepage ViewModel and we do the same for checking if the Empty list indicator label is visible as well. 😉

There you go, you’ve just created your first UnitTest case for your Xamarin.Forms app!

Mixing it up!

Since our Xamarin.Forms runtime is mocked, you can mix and mingle among the actual UI Elements of your App and DI Container objects.

You see in the previous demo code, how I’ve accessed NavigationStack of the app using App.MainPage instance, as well as you can see how I’m using the Current active Page instance to access its child element, which is a Label element and check its rendered value as follows…

// Get the value in ViewModel
var viewingTextItem = 
   App.Container.Resolve
      <ViewTextPageViewModel>().TextItem;

// Check TextTitle Label value
var textTitleLabel = 
((Label)((Grid)
	((ViewTextPage)GetCurrentPage())
		  .Content).Children.First());
textTitleLabel.Text.ShouldBe(viewingTextItem.TextTitle);

You can see how I have retrieved the Label element by traversing through the Page object, and comparing the results with the value I’ve retrieved from the ViewModel object. So you can mix and match these two approaches in harmony for implementing complicated test cases easily!

App Properties…

Thanks to the mocked Xamarin.Forms runtime we’re able to access most of its functionality as it is in our test cases, which goes to the Application Properties as well.

As an example here I am clearing out my Application Properties on TearDown event after any given test case is executed.

// Clear App properties in memory
Application.Current.Properties.Clear();
await Application.Current.SavePropertiesAsync();

Navigation…

The Navigation in my demo project is handled by Prism, which uses the default Xamarin.Forms navigation underneath it. The Xamrin.Forms.Mock seem to be handling it pretty well as well. So you wouldn’t be need to do any special handles in the test code.

[Test]
public void NavigatingToNewTextPageTest()
{
	...

	// Navigating to New Text page
	App.Container.Resolve<HomePageViewModel>()
		.GoToNewTextPageCommand.Execute();

	// Am I in the New Text page
	GetCurrentPage().BindingContext.GetType()
		.Name.ShouldBe(nameof(NewTextPageViewModel));
}

Hence I could simply call up the usual Navigation Commands that I use on the Button element, here in my unit test code as well. 😉 Navigation will behave as expected!

Mockin’ Services!

Like I mentioned before if you have a Service which relies on platform specific features, then you need to mock those services instances in your testing environment. In my demo I’m using a LocationService, which I have mocked in the my test code as follows…

/// <summary>
/// Mocked Location Service
/// </summary>
public class MockLocationService : ILocationService
{
	public Task<Location> GetLocation()
	{
		// Mock location data
		return Task.FromResult(new Location(0.11111, 0.22222));
	}
}

Also do not forget registration in the TestApp instance which I showed before…

// register mocked ILocationService
containerRegistry.RegisterSingleton
      <ILocationService, MockLocationService>();

Now with that, every time the actual App code try to resolve the LocationService it will get the MockedLocationService object and use its mock data during the test executions. You could also use an awesome library like moq for mocking services and data as well.

Fake em!

If you have actual API calls going in or out of your app, you shouldn’t use them in your unit tests, hence it could cause for slowing down the test executions, and would consume a lot of resources, keeping in mind tests are meant to be executed repeatedly.

So you need to create Mocked Services for those API bound calls, with fake data sets attached to them, so in test code, they would be using the fake data or fake responses instead. 😉 Another reason to use moq library! There are others as well, Faker.net and Bogus are also popular!

Reduce the repetition!

There could be repetitive steps in these Unit Test cases, therefore you can improve the code by extracting out those common repetitive test steps into separate methods or extensions.

public class ViewTextPageTests : BaseTest
{
	[Test]
	public void NavigatingToViewTextPageTest()
	{
		...
		// Create a new Text item
		var textItem = CreateSampleTextItem();
		...
	}

	[Test]
	public void ViewTextDetailsAndGoBackPageTest()
	{
		...
		// Create a new Text item
		var textItem = CreateSampleTextItem();
		...
	}

	public TextItem CreateSampleTextItem()
	{ ... }
}

As an example in both my test cases above, I need to create a new TextItem object, hence I’ve extracted it out to a common method which is used in both, reducing the repetition.

Here’s another example where I’ve created the following helpers in BaseTest class,

/// <summary>
/// Returns the active Page
/// </summary>
/// <returns></returns>
public static Page GetCurrentPage()
{
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	return (Page)navigationStack.Last();
}

/// <summary>
/// Returns the active ViewModel
/// </summary>
/// <returns></returns>
public static ViewModelBase GetCurrentViewModel()
{
	var navigationStack = ((NavigationPage)App.MainPage).Navigation.NavigationStack;
	return (ViewModelBase)navigationStack.Last().BindingContext;
}

Allowing me to retrieve the current active Page or the ViewModel directly.

Before and After Test Case…

Most Testing frameworks provides you with Before and After hooks for a given Test Case, where as in my demo, NUnit provides [Setup] and [TearDown] subsequently.

public class BaseTest
{
	[SetUp]
	public void Setup()
	{
		// Set up steps
	}
	
	[TearDown]
	public async Task TearDown()
	{
		// Teardown steps
	}
     
    ...
}

As I’ve shared before I’ve set up the [Setup] attribute in the BaseTest class, allowing me to reinstantiate TestApp instance before each Test Case executes.

[TestFixture]
public class HomePageTests : BaseTest
{
	[SetUp]
	public new void Setup()
	{
		// Page specific Setup
	}

	...
}

You can override the set up in your Page specific test class and set up the required customized setting up as well. This was you can also share data across the whole flow of the page test scope without resetting the TestApp instance. Quite a handy trick to keep in mind! 😉

Finalizing…

So all of this awesomeness is committed into my github repo:

Github repo:
github.com/UdaraAlwis/XFWithUnitTest

Since I took the Page based pattern for organising my unit test cases, here’s the set of test classes I ended up creating for each page.

Under the Test folder I’ve placed all my test class, but you can restructure this hierarchy as you please, even have sub folders containing different sets of test as well… 😉

So in my demo below are the test classes that represents each page…

  • Home Page : HomePageTests
  • New Text Page: NewTextPageTests
  • View Text Page: ViewTextPageTests

Maintaining a good readability of your test cases can definitely benefit you in the long run! 😉

Once you open up your Test Runner, either built in Visual Studio Test Runner or even a 3rd Part Tool like Resharper Test Runner, all your tests should be discoverable as below…

All the UnitTest classes are shown with all the test cases in them, ready to be executed! 😉

Demo time!

So let’s fire up these UnitTests…

Woah! What a satisfying thing to watch eh! 😀

Github repo:
github.com/UdaraAlwis/XFWithUnitTest

Once again feel free to grab it on my github! 😉

Conclusion

You can easily implement UnitTesting in Xamarin.Forms just like any other .NET project, and there are plenty of ways to do it. Mocking Xamarin.Forms runtime and implementing our UnitTests on top of that, is a great way to ensure that our tests are executing as close as it gets to the real app runtime. You can easily integrate Xamarin.Forms.Mocks library with pure Xamarin.Forms or along side any other MVVM Library to set up your UnitTests!

We need to make sure to follow best practices and maintain clean, easy to read, test code across all our UnitTesting implementations. You can take different approaches to organising your test cases, while I personally believe Page-Context based pattern provides more clarity.

 Hope this documentation out of my own experience helps any of you fellow Xamarin.Forms devs out there! Share the love! 😀 Cheers yol!

1 thought on “XAMVVM-02 TDD UnitTesting with Xamarin.Forms!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.