Dependency Injection is one of the most elegant tool to inject dependencies at runtime, which makes the application more loosely-coupled. It also helps in building modularized code that improves testability by enabling unit-testing on modules.
In this post, I will be creating a complicated dependency setup to explain the idea of how dependencies can be injected using an Azure Function. Then, I will mock these dependencies to test the setup using Moq and xUnit. This post will help you to understand how dependency injection setup can be seamlessly simulated using these amazing frameworks.
You can use the below GitHub Repo for referring the complete code mentioned here.
azure-dev-projects/MoqXunitWithDI
First, let’s understand the modularized application which we will be building.
Table of contents
Building Custom Application with Dependencies
We need to build a complicated setup of dependencies to explain the usage of dependency injection. In order to do this, we will be implementing the below shown setup.

We will be creating a FooModule class library to get all the required classes in one place as shown below.

We will first start with our interfaces.
-
IFooCollection→ This interface will help in providing all theFooRegistrationobjectspublic interface IFooCollection { public IEnumerable<FooRegistration> GetAllRegistrations(); } -
IFooWork→ This interface will help in providingFooResultobject after doing some simulated checkingpublic interface IFooWork { Task<FooResult> CheckFooAsync(string param1, string param2, FooContext context, FooToken fooToken); } -
IFooLogicImplementer→ This interface will help in designing ourFooLogicImplementerthat will giveFinalResultafter executing some logicpublic interface IFooLogicImplementer { Task<FinalResult> ExecuteLogic(); }
These interfaces are the dependencies using which we will implement our FooLogicImplementer as shown below.
//FooLogicImplementer.cs
public class FooLogicImplementer: IFooLogicImplementer
{
private readonly List<FooRegistration> _foos = new List<FooRegistration>();
public FooLogicImplementer(IEnumerable<IFooCollection> data)
{
foreach(var foo in data)
{
_foos.AddRange(foo.GetAllRegistrations());
}
}
// simulate logic
// We need to test this functionality using unit test
public async Task<FinalResult> ExecuteLogic()
{
List<FooResult> data = new List<FooResult>();
foreach(var _foo in _foos)
{
data.Add(await _foo.Exec());
}
var isAllGood = true;
foreach(var result in data)
{
if(result.Val == FooResultVals.BadResult)
{
isAllGood = false;
}
}
if (isAllGood)
{
return new FinalResult
{
FinalRes = "Good",
Data = data
};
}
else
{
return new FinalResult
{
FinalRes = "Bad",
Data = data
};
}
}
}
The above implementation is following below process:
- Collection of
IFooCollectionwill be injected using dependency injection. - Fire
GetAllRegistrationsof eachIFooCollectionto getFooRegistrationobjects. - For each of the
FooRegistrationobjects, callexecfunction and collectFooResultobjects. - If all the results are
Good, then set final result to beGood - Otherwise, if any of the result is
Bad, the set final result to beBad
As you can see, this implementation is dependent on several interfaces to derive the final result to be good or bad. Hence, in order to test this implementation, we would need to mock these dependencies.
You can view/download the entire module using below GitHub URL:
azure-dev-projects/MoqXunitWithDI/FooModule
Now, we are ready to test this module. We will first test it using Azure Functions to see if our dependencies can be injected efficiently and then use unit testing.
Testing Custom Application with Dependencies
Our objective is to test the
FooLogicImplementerclass and itsExecuteLogicfunctionality by verifyingFinalResult.
Test using Azure Function
We can test whether our dependencies are working by creating an Azure function application. The project can be viewed using the below GitHub URL:
azure-dev-projects/MoqXunitWithDI/FooLogicFnApp

We will inject the above dependencies during startup using our custom implementations as shown below.
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// inject dependencies
builder.Services.AddScoped<IFooCollection, FooLogic1>(sp =>
{
return new FooLogic1(new FooWork1());
});
builder.Services.AddScoped<IFooCollection, FooLogic2>(sp =>
{
return new FooLogic2(new FooWork2());
});
// inject implementer
builder.Services.AddScoped<IFooLogicImplementer, FooLogicImplementer>();
}
}
Here, FooLogic1 derives from IFooCollection and implements GetAllRegistrations function to generate List<FooRegistration> as shown below.
public class FooLogic1 : IFooCollection
{
private readonly IFooWork _fooWork;
public FooLogic1(IFooWork fooWork)
{
_fooWork = fooWork;
}
public IEnumerable<FooRegistration> GetAllRegistrations()
{
return new List<FooRegistration>
{
new FooRegistration("logic_reg_1_1", _fooWork, new FooToken(), new List<string> {"tag1", "tag2"}),
new FooRegistration("logic_reg_1_2", _fooWork, new FooToken(), new List<string> {"tag1", "tag2"})
};
}
}
Similarly, FooLogic2 can be implemented to generate List<FooRegistration>.
Now, each FooRegistration takes IFooWork instance which needs to be provided. This instance sets whether it is either a good result or bad result as shown below for FooWork1. Here, it is setting a GoodResult.
public class FooWork1 : IFooWork
{
public Task<FooResult> CheckFooAsync(string param1, string param2, FooContext context, FooToken fooToken)
{
return Task.FromResult(new FooResult(param1, param2, FooResultVals.GoodResult));
}
}
Similarly, we can create FooWork2 that also derives from IFooWork and return a FooResult with a BadResult as shown below.
public class FooWork2 : IFooWork
{
public Task<FooResult> CheckFooAsync(string param1, string param2, FooContext context, FooToken fooToken)
{
return Task.FromResult(new FooResult(param1, param2, FooResultVals.BadResult));
}
}
We can now start and test our function app by hitting the endpoint using postman or any other REST client. Since one of our result returned by our IFooWork is good and one is bad, we should get the final result as bad result as shown below.

This shows that our dependencies are being injected correctly and the logic of FooLogicImplementer is working as required. But, we need to test it for other scenarios as well, such as,
- If all
IFooWorkare good result, then final result should be good. - If some
IFooWorkare good result and some are bad, then final result should be bad. - If all
IFooWorkare bad result, then final result should be bad. - If 1
IFooCollectionis registered, then 1 is checked properly. - If 2
IFooCollectionare registered, then 2 are checked properly.
Looking at these scenarios, I hope you can clearly see the problem with Azure function based testing. We need to change our code every time - create the required implementation for the scenario, run the application, hit it via a REST client and then view the results. Moreover, this approach is unlikely to scale well when we’ll have 10-20 scenarios.
So, a better way is to do unit-testing. We can create unit tests for each of the above scenarios, and then run them in isolation to verify the functionality. But, how do you inject these dependencies to test our FooLogicImplementer class? That’s where Moq library will enter!
Test using xUnit and Moq
First, we will create a unit test C# project (.NET core 3.1 LTS) and install following nuget packages:
- Moq (4.16.1)
- xunit (2.4.1)
- xunit.runner.visualstudio (2.4.3)
You can view the entire test project using the below GitHub URL:
azure-dev-projects/MoqXunitWithDI/UnitTestLogicImplementer
Now, if you are wondering why xUnit has gained more popularity than MSTest - it is mostly because of the support of Theory attribute and its pluggable functionality in any project.
For more details, checkout this blog: The xUnit tool has gained popularity over MSTest
So, let’s try to create our 1 first unit test that will cover the scenario:
If all
IFooWorkare good result, then final result should be good.
In order to test the above scenario, we need to create an object of FooLogicImplementer class. But, if you look at the constructor, it needs IEnumerable<IFooCollection> data to instantiate. Hence, we will mock these dependencies so that we can create the required object.
-
Mock
IFooWorkto get aGoodResult.// setup work 1 to be good result _work1 = new Mock<IFooWork>(); _work1.Setup(s => s.CheckFooAsync("logic_reg_1_1", It.IsAny<string>(), It.IsAny<FooContext>(), It.IsAny<FooToken>())) .Returns(Task.FromResult(new FooResult("logic_reg_1_1", It.IsAny<string>(), FooResultVals.GoodResult)));This setup will ensure that whenever mocked object of
IFooWorkis used to fireCheckFooAsyncfunction with first parameter as"logic_reg_1_1"and other parameters could be any valid value, then it should result aFooResultthat will haveGoodResult. So, rather than implementing the logic, we have mocked the inputs and outputs as per our requirement. - Similarly, Mock another
IFooWorkto get a good result. -
Create a
FooRegistrationcollection which will take these mockedIFooWorkobjects.var data = new List<FooRegistration>() { new FooRegistration("logic_reg_1_1", _work1.Object, new FooToken(), new List<string> {"tag1", "tag2"}), new FooRegistration("logic_reg_1_2", _work2.Object, new FooToken(), new List<string> {"tag1", "tag2"}) }; -
Mock the
IFooCollectionwhich will return the above collection whenGetAllRegistrationsis fired._fooCollection.Setup(s => s.GetAllRegistrations()).Returns(data); -
Using the above mocked dependencies, create an object of
FooLogicImplementerand execute its logic function.// act var testImplementer = new FooLogicImplementer(new List<IFooCollection> { _fooCollection.Object }); var res = await testImplementer.ExecuteLogic(); -
Assert the final result.
Xunit.Assert.Equal("Good", res.FinalRes);
So, the final implementation of the scenario can be stated as follows:
public class FooLogicImplementerTests
{
private readonly Mock<IFooCollection> _fooCollection;
private Mock<IFooWork> _work1;
private Mock<IFooWork> _work2;
public FooLogicImplementerTests()
{
_fooCollection = new Mock<IFooCollection>();
}
[Fact]
public async void If_All_Good_Return_Good()
{
// mock dependencies
// setup work 1 to be good result
_work1 = new Mock<IFooWork>();
_work1.Setup(s => s.CheckFooAsync("logic_reg_1_1", It.IsAny<string>(), It.IsAny<FooContext>(), It.IsAny<FooToken>()))
.Returns(Task.FromResult(new FooResult("logic_reg_1_1", It.IsAny<string>(), FooResultVals.GoodResult)));
// setup work 2 to be good result
_work2 = new Mock<IFooWork>();
_work2.Setup(s => s.CheckFooAsync("logic_reg_1_2", It.IsAny<string>(), It.IsAny<FooContext>(), It.IsAny<FooToken>()))
.Returns(Task.FromResult(new FooResult("logic_reg_1_2", It.IsAny<string>(), FooResultVals.GoodResult)));
// Add some FooRegistrations
var data = new List<FooRegistration>()
{
new FooRegistration("logic_reg_1_1", _work1.Object, new FooToken(), new List<string> {"tag1", "tag2"}),
new FooRegistration("logic_reg_1_2", _work2.Object, new FooToken(), new List<string> {"tag1", "tag2"})
};
_fooCollection.Setup(s => s.GetAllRegistrations()).Returns(data);
// act
var testImplementer = new FooLogicImplementer(new List<IFooCollection> { _fooCollection.Object });
var res = await testImplementer.ExecuteLogic();
// assert
Xunit.Assert.Equal("Good", res.FinalRes);
}
}
Similarly, we can do mocking of these dependencies again and test for all of the above stated scenarios as shown below.

The implementation of other test cases are very similar to the one showed here. You can review them using the below URL:
MoqXunitWithDI/UnitTestLogicImplementer/FooLogicImplementerTests.cs
This completes the idea of using Moq and xUnit with complicated dependency injection setup. As you can see, it can be really helpful to create unit tests for testing multiple scenarios, rather than updating the code again and again to cover all cases.
Cheers!
Leave a comment