Telerik blogs

Unit tests are a vital step in development, allowing you to check small, specific functionalities. Here’s how to get started in .NET MAUI.

There are different types of tests in software applications, including unit tests, integration tests and user interface tests. Today, we’ll focus on unit tests, one of the most common types.

Unit tests allow us to examine small pieces of code individually—such as functions or methods—to verify specific functionalities. This checks that these code units behave as expected and helps prevent errors from spreading throughout the application.

The main advantages of unit testing include:

  • Early error detection
  • Reduction of defects in production
  • Improved code quality

✍️ Recommendation

When developing your app, it’s recommended to incorporate unit tests into your workflow. Add them to your “must-have” list before considering a piece of code functionality complete. These tests can serve double duty as design documentation and functional specifications.

Integrating xUnit into Your .NET MAUI Solution

First of all, what is xUnit? xUnit is a widely-used unit testing framework for writing and running automated tests in .NET applications.

To add xUnit tests to your .NET MAUI solution, you have two options:

  1. Use Visual Studio to add a new xUnit test project to your solution. Navigate to Web and Console ➡️ Test ➡️ xUnit Test Project.

  2. Create the xUnit project from the .NET CLI. For more information, see Unit testing C# in .NET using dotnet test and xUnit.

The created project must include a project file (.csproj) that resembles the following example:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
	    <TargetFramework>net8.0</TargetFramework>
	    <ImplicitUsings>enable</ImplicitUsings>
	    <Nullable>enable</Nullable>
	    
	    <IsPackable>false</IsPackable>
	    <IsTestProject>true</IsTestProject>
    </PropertyGroup>

    <ItemGroup>
	    <PackageReference Include="coverlet.collector" Version="6.0.0" />
	    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
	    <PackageReference Include="xunit" Version="2.5.3" />
	    <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
    </ItemGroup>
    
    <ItemGroup>
	    <Using Include="Xunit" />
    </ItemGroup>

</Project>

⚠️ A key element to note in the code is the TargetFramework property. This sets the project’s framework and should correspond to the latest version of .NET installed on your computer.

There are two main approaches to structuring your application for unit testing:

  1. The code you’ll test is in a .NET MAUI class library project.
  2. The code you’ll test is in a .NET MAUI application project.

To add unit tests in a .NET MAUI project, you need to modify the build properties. This applies whether the code you’re testing is in the application project or a class library used by the application. Specifically, add the $(TargetFramework) value from the xUnit test project file to the $(TargetFrameworks) property in the corresponding project file (either the application or the class library).

Below I show you an example of how it should look:

<TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>

In this example, we added net8.0 to $(TargetFrameworks). You’ll need to add a reference to your .NET MAUI class library or app project from your xUnit test project.

To target the .NET MAUI application project, we need one additional step. We must modify the .NET MAUI app project to prevent it from generating an executable for the target framework used by the xUnit test project. Simply add a condition to the $(OutputType) build property in the .NET MAUI app project file, as follows:

<OutputType Condition="'$(TargetFramework)' != 'net8.0'">Exe</OutputType>

Let’s Write Unit Tests

xUnit supports two main types of unit tests: facts and theories.

Testing type - Facts, Attribute - Fact , Description: Tests that are always true, which test invariant conditions. Testing type - Theories, Attribute - Theory , Description: Tests that are only true for a particular set of data.

Unit tests must be placed in your xUnit test project and must contain either the [Fact] or [Theory] attribute, depending on the type of test you need to create.

Fact

The [Fact] attribute designates a method as a unit test.

Let’s examine an example using [Fact], which denotes tests with invariant conditions—those that are always true. Our example includes two scenarios:

  1. PassTest Method: This method demonstrates that 2 + 2 equals 4, resulting in a successful test. To verify this, we use the Assert class, which allows us to check if the result of an operation or the state of an application matches our test expectations.

  2. FailingTest: This method attempts to assert that 2 + 2 equals 5, which is incorrect and results in a failed test. It also uses the Assert class to verify the result.

Let’s see what this looks like in code:

namespace MyUnitTests
{   
    public class MyTests
    {
	    [Fact]
	    public void PassingTest()
	    {
		    Assert.AreEqual(4, 2+2);
	    }
	    
	    [Fact]
	    public void FailingTest()
	    {
		    Assert.AreEqual(5, 2+2);
	    }
    }
}

Theory

Unlike [Fact], which is a test executed only once, the [Theory] attribute allows you to test the same logic with multiple inputs, verifying that the code works correctly in various scenarios.

In the example below, we test different scenarios using the [InlineData] attribute to specify the data passed as parameters to the test method. We’ll create a MyTheoryTest method that accepts an integer value as a parameter (the same parameter you pass using [InlineData]).

After passing all the values you want to test, you simply indicate what you want to confirm—in this case, whether the value passed by parameter is an odd number.

Here’s how it looks in code:

namespace MyUnitTests 
{
    public class MyTests 
    {
	    [Theory] 
	    [InlineData(3)] 
	    [InlineData(4)] 
	    [InlineData(5)]
	    
	    public void MyTheoryTest(int value)  
	    { 
		    Assert.True(value % 2 == 1); 
	    } 
    }
}

And your tests are done! 😎

Arrange-Act-Assert (AAA) Pattern

As you’ve seen in the previous examples, these tests follow a specific structure. This organization is based on the Arrange-Act-Assert pattern.

Unit tests typically follow this Arrange-Act-Assert pattern, which makes the tests readable, self-describing and coherent. Let’s explore their definitions:

Step: Arrange; Description: Set up the test environment by initializing objects and setting data values for the method being tested. Step: Act; Description: Call the method being tested with the necessary parameters. Step: Assert; Description: Verify that the method under test behaves as expected.

Let’s examine one of the examples above to better understand each step in the code:

Testing example: Arrange: In this stage, you set up all the necessary information to execute the test. - Example:    int number1 = 2; int number2 = 2; int expectedResult = 4;  -- Act: Executes the functionality or behavior that you are testing. - Example: **int actualResult = Add(number1, number2, Assert: Checks whether the result of the action matches the expected result. Example: Assert.Equal(expectedResult, actualResult);

In this straightforward manner, your code follows the Arrange-Act-Assert (AAA) pattern. 🥰

Some Highlights

  • Unit tests are highly effective at catching regression—instances where previously working functionality has been disrupted by a faulty update.
  • Perform one operation per unit test. As tests become more complex, they become harder to verify. By limiting each unit test to a single issue, your tests are repeatable, isolated and run more quickly. For more information about unit testing best practices, see here.

How to Run Unit Tests

These tests can be run in two ways:

Wrap-up

That’s all! 🎊 You already know how to start with unit testing in your .NET MAUI apps!

Thanks for reading this article! 💚💕

See you next time! 🙋‍♀️

References

This article was based on the official documentation:


LeomarisReyes
About the Author

Leomaris Reyes

Leomaris Reyes is a Software Engineer from the Dominican Republic, with more than 5 years of experience. A Xamarin Certified Mobile Developer, she is also the founder of  Stemelle, an entity that works with software developers, training and mentoring with a main goal of including women in Tech. Leomaris really loves learning new things! 💚💕 You can follow her: Twitter, LinkedIn , AskXammy and Medium.

Related Posts

Comments

Comments are disabled in preview mode.