Unit Testing in Xamarin with NUnit
Introduction
Today when working in an agile development project, the stakeholders usually wants us to deliver features rapidly and frequently. We also need to ensure a high quality level of the released features and be able to safely refactor the code base due to changed requirements.
This makes it impossible to rely only on manual testing, and we need to automate as much testing as possible.
One type of automated testing is the unit test, where we isolate one unit (module/class) at a time, and test that it behaves as aspected. Sounds simple right!
There are a lot of tools and frameworks available to make it easy to configure, mock and unit test out there. In this article we will have a quick look at NUnit, NSubstitute and Autofac.
We at Avalon Innovation are more than 250 specialists all over Scandinavia who are passionate about developing ground-breaking, innovative product and system solutions that really make a difference. Since 1997 we have tackled many challenging and difficult assignments, which have provided us with broad technical expertise and unique insights into innovation.
The Demo Project
Download the demo project from my GitHub for the complete source code from this article.
Dependency Injection
When we want to test a single unit we often need to remove or replace that units dependencies. This is called mocking! We replace the dependencies with something else that behaves in a predictive way.
Dependency injection or Inversion of Control (IoC) is an architectural pattern where a units dependencies are provided to the unit instead of being created inside the unit.
Lets look at an example!
public interface IProfileService
{
Profile GetProfile();
}
public class ProfileService : IProfileService
{
private readonly IProfileRepository _profileRepository;
public ProfileService(IProfileRepository profileRepository)
{
_profileRepository = profileRepository;
}
public Profile GetProfile()
{
return _profileRepository?.GetProfile();
}
}
In the example above the class ProfileService is dependent on the interface IProfileRepository, and that gets injected to the constructor. This is called constructor injection and is a common way to do dependency injection.
This is really great because now ProfileService is only aware of IProfileRepository and not with the exact implementation! In production it will probably be implemented with a class that fetches and saves profile information to a database or a web service, but in a unit test scenario we can send a mocked implementation of IProfileRepository to ProfileService to isolate it from its dependency!
In this article I will use Autofac for the configuration of dependencies. A tool is perhaps not necessary, but it makes our job a bit easier.
Testing a simple unit
The demo project has a class called Profile that contains both data about a users profile and some calculations of daily recommended energy, carb, fat and protein intake. These calculations are perfect for unit testing!
The Profile class does not have any external dependencies that we need to mock, we just need to create and instance, add some data, run the calculations and validate the results.
[TestFixture]
public class TestProfileCalculations
{
private Profile _maleProfile;
[SetUp]
public void SetUp()
{
_maleProfile = new Profile
{
BirthDate = DateTime.Now.AddYears(-47),
Gender = GenderTypes.Male,
Weight = 105,
Height = 183,
PhysicalActivity = PhysicalActivityTypes.Moderate
};
}
[Test]
public void TestCalculateDailyEnergyIntakeMale()
{
// ARRANGE
// ACT
var result = (int)Math.Round(_maleProfile.CalculateDailyEnergyIntake());
// ASSERT
Assert.AreEqual(3268, result);
}
}
Lets create a class called TestProfileCalculations! First we need to mark it with [TestFixture] for NUnit to find it. Then we create a new instance of the Profile class in the method marked with [SetUp].
Finally we create a test method. In this case we want to test that the calculated daily energy intake for this profile is 3268 kcal. We know that this is the correct value and we want to test that the calculations are correct.
A unit test usually consists of three steps. Arrange data before the test, act on the subject under test and assert that the results of the test is what we expected.
In this case we don't need to arrange any more, we have the created profile. Instead we call the method and assert that the returned value is equal to 3268 kcal. Done!
Mocking dependencies
In the demo project we have a class called ShowProfileViewModel that calls a couple of methods in IProfileService to load and save a users profile. We need to write a test to ensure that this is done in a correct way!
public interface IShowProfileViewModel
{
Profile CurrentProfile { get; }
void LoadProfile();
void SaveProfile();
}
public class ShowProfileViewModel : IShowProfileViewModel
{
private readonly IProfileService _profileService;
public ShowProfileViewModel(IProfileService profileService)
{
_profileService = profileService;
}
public Profile CurrentProfile { get; private set; }
public void LoadProfile()
{
if (_profileService.HasProfile() == false)
{
CurrentProfile = new Profile();
return;
}
CurrentProfile = _profileService.GetProfile();
}
public void SaveProfile()
{
_profileService.SaveProfile(CurrentProfile);
}
}
There are some logic here.
When LoadProfile() is called and a profile is missing, a new one is created and the loaded or created profile is then accessible with the property CurrentProfile.
When SaveProfile() is called the data in CurrentProfile is sent to IProfileService for processing.
Lets write some tests!
private IProfileRepository _profileRepository;
private IProfileService _profileService;
private IShowProfileViewModel _subject;
First we create some variables! One for the subject and then one for IProfileService and one for IProfileRepository.
[SetUp]
public void SetUp()
{
// Create the builder
var builder = new ContainerBuilder();
// Register a mock instance for IProfileRepository
_profileRepository = Substitute.For<IProfileRepository>();
builder.RegisterInstance(_profileRepository)?.As<IProfileRepository>()?.SingleInstance();
// Register a mock instance for IProfileService
_profileService = Substitute.For<IProfileService>();
builder.RegisterInstance(_profileService)?.As<IProfileService>()?.SingleInstance();
// Register the subject
builder.RegisterType<ShowProfileViewModel>()?.As<IShowProfileViewModel>()?.SingleInstance();
// Build the IoC container
var container = builder.Build();
// Resolve the subject instance
_subject = container.Resolve<IShowProfileViewModel>();
}
Then we setup the tests in a number of steps.
- We create a ContainerBuilder with Autofac to register our types in
- We use NSubstitute to create a mock object from IProfileRepository and add that to Autofac. NSubstitute makes it easy for us to configure in runtime how the mock objects behave.
- We use NSubstitute to create a mock object from IProfileService and add that to Autofac as well.
- We register the subject in Autofac with its normal implementation, because that is what we want to test.
- After the registration of types is done, we resolve the subject instance.
Now we have an instance of the test subject (ShowProfileViewModel) and mocked instances of IProfileRepository and IProfileService. When the new instance of ShowProfileViewModel is created Autofac will automatically inject the mocked instance of IProfileService to its constructor.
[Test]
public void TestLoadProfileWithEmptyProfile()
{
// ARRANGE
_profileService.HasProfile().Returns(false);
// ACT
_subject.LoadProfile();
// ASSERT
Assert.NotNull(_subject.CurrentProfile);
Assert.AreEqual(Profile.DefaultGender(), _subject.CurrentProfile.Gender);
Assert.AreEqual(Profile.DefaultBirthDate(), _subject.CurrentProfile.BirthDate);
Assert.AreEqual(Profile.DefaultPhysicalActivity(), _subject.CurrentProfile.PhysicalActivity);
Assert.AreEqual(0, _subject.CurrentProfile.Weight);
Assert.AreEqual(0, _subject.CurrentProfile.Height);
}
Lets test that ShowProfileViewModel behaves correctly when we call LoadProfile().
We start with configuring that the method HasProfile() in IProfileService should always return false. This is one of the nice things that NSubstitute gives us! The ability to change mocked objects behavior easily.
Then we act on the test subject and call the method LoadProfile().
Now because a profile does not exist ShowProfileViewModel will create a new instance of Profile, right? This we can assert!
[Test]
public void TestLoadProfileWithExistingProfile()
{
// ARRANGE
var profile = new Profile
{
BirthDate = DateTime.Now.AddYears(-45),
Gender = GenderTypes.Male,
Weight = 100,
Height = 183,
PhysicalActivity = PhysicalActivityTypes.Moderate
};
_profileService.HasProfile().Returns(true);
_profileService.GetProfile().Returns(profile);
// ACT
_subject.LoadProfile();
// ASSERT
Assert.NotNull(_subject.CurrentProfile);
Assert.AreEqual(profile.Gender, _subject.CurrentProfile.Gender);
Assert.AreEqual(profile.BirthDate, _subject.CurrentProfile.BirthDate);
Assert.AreEqual(profile.PhysicalActivity, _subject.CurrentProfile.PhysicalActivity);
Assert.AreEqual(profile.Weight, _subject.CurrentProfile.Weight);
Assert.AreEqual(profile.Height, _subject.CurrentProfile.Height);
Assert.AreEqual(profile.Age, _subject.CurrentProfile.Age);
Assert.AreEqual(45, _subject.CurrentProfile.Age);
}
Now we can continue to write a test for when LoadProfile() is called and a profile exists. HasProfile() should return true and GetProfile() should return a known profile so we can assert that the correct profile is added to ShowProfileViewModel. Done!
For more examples please look at the demo project on GitHub!
Conclusions
Unit testing is necessary to deliver features frequently while ensuring a high quality of the delivered product. Unit tests are easy to write if we use an architecture that enables us to mock dependencies and isolate the units that needs to be tested.
More info on the frameworks used in this article can be found online:
https://nunit.org/
https://nsubstitute.github.io/
https://autofac.org/
Happy testing!