Hi Everyone!

In this post, we will discuss about the alternative framework for mocking. This post is adoptation of this which is using Moq.

You can find the full series of how to perform unit and integration tests for Azure Blob Storage using Azurite Test Containers, and xUnit.

Getting started with testing for Azure Blob Storage : Dependency Injection

Getting started with testing for Azure Blob Storage : Unit Test with help of Moq

This Post - Getting started with testing for Azure Blob Storage : Unit Test with help of FakeItEasy (Alternative to MoQ)

Getting started with testing for Azure Blob Storage : Integration Test with help of TestContainers and Azurite

Getting started with testing for Azure Blob Storage : Mocking Azure Blob/File Storage SDK

Let’s get started.

I am late in the party, but you must be aware of the fuss around the Moq. If you are not aware, let me give you a brief detail about it.

Moq maintainer Daniel Cazzulino has introduced a spyware in the Moq library from version 4.20.0, which sends your hashed email address to the SponsorLink CDN. You can find the full story here

As of today, latest version of Moq is 4.20.69. In which, the spyware is removed. However, the damage is already done. Also, not sure about the future if they will introduce the spyware again or not. So, I have decided to move away from Moq and use some other mocking framework like FakeItEasy or NSubstitute.

In this post, we will use FakeItEasy to perform unit test for Azure Blob Storage. FakeItEasy and NSubstitute are the two most popular mocking framework alongwith Moq. I have decided to use FakeItEasy because of it’s license. FakeItEasy is licensed under MIT and NSubstitute is licensed under 2-Clause BSD. I am not a lawyer, but seems like there not much difference between these two licenses. However, I am more comfortable with MIT license.

We will use the same code base we used in the previous post. So, if you have not read the previous post, I would recommend to read it first before proceeding further as we will skip the code part and focus on the testing part.

First, we will remove the reference of Moq from the project. Then we will add FakeItEasy as nuget package. Here is the code snippet of csproj for the project SystemUnderTest -

SystemUnderTest.UnitTest.csproj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
    <PackageReference Include="FakeItEasy" Version="7.4.0" />
    <PackageReference Include="xunit" Version="2.4.2" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="coverlet.collector" Version="3.1.2">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\SystemUnderTest\SystemUnderTest.csproj" />
  </ItemGroup>

</Project>

Writing Unit Test

We have setup all tools and framework and ready to write our first test case. Let’s try to understand what are the scenarios we want to test. We have two scenarios in our mind, one is when the file is uploaded successfully and another is when the file upload fails. We will write test cases for each scenario.

If you notice UploadFileToAzBlob writes the result to console. so,let’s prepare our UnitTests.cs to handle this -

UnitTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
using Moq;
using SystemUnderTest.Interface;

namespace SystemUnderTest.UnitTest;

public class UnitTests
{
   private readonly StringWriter Output = new StringWriter();
    public UnitTests()
    {
        Console.SetOut(Output);
    }
}

All set. Let’s write our first test case.

Test case 1 - File upload success

If you remember, very beginning of this post we made a change in UploadFileToAzBlob method. We removed the dependency on IServiceProvider and added dependency on IAzBlobService.

So, we will create a fake object of IAzBlobService and pass it to UploadFileToAzBlob method.

UnitTests.cs
1
2
3
4
5
6
7
8
[Fact]
public async Task File_Upload_Success()
{
  var azBlobService = A.Fake<IAzBlobService>();
  A.CallTo(() => azBlobService.UploadFileToAzBlobAsync(A<string>._)).Returns(true);
  await Program.UploadFileToAzBlobAsync(azBlobService);
  Assert.Contains("File uploaded successfully", Output.ToString());
}

At line 4, we are creating a fake object of IAzBlobService.

At line 5, we are setting up the fake object to return true when UploadFileToAzBlob method is called.

At line 6 we are calling UploadFileToAzBlob method and passing the fake object of IAzBlobService.

At line 7, we are asserting that the output contains the string File uploaded successfully.

At this stage, we have completely ignoring the implementation of UploadFileToAzBlob method. We are only testing the output of the method and not the implementation. This is the beauty of mocking framework. We can test the output of the method without worrying about the implementation.

Test case 2 - File upload failure

Similarly, we can write the test case for the scenario when the file upload fails.

UnitTests.cs
1
2
3
4
5
6
7
8
[Fact]
public async Task File_Upload_Failure ()
{
  var azBlobService = A.Fake<IAzBlobService>();
  A.CallTo(() => azBlobService.UploadFileToAzBlobAsync(A<string>._)).Returns(false);
  await Program.UploadFileToAzBlobAsync(azBlobService);
  Assert.Contains("File upload failed", Output.ToString());
}

Here, the only difference is we are setting up the fake object to return false when UploadFileToAzBlobAsync method is called.

Outro

That’s it. We have written two test cases for the method UploadFileToAzBlobAsync. We have used FakeItEasy to mock the dependency IAzBlobService and xUnit to write the test cases.

However, we have not tested the implementation of UploadFileToAzBlobAsync method. We have only tested the output of the method.

We will write the test cases for the implementation of UploadFileToAzBlobAsync method using FakeItEasy in another post.

FakeItEasy has great documentation. You can find it here.

You can find the source code here.