Net Core: Dependency Injection in Integration Test [duplicate] - c#

This question already has answers here:
Unit Testing IServiceCollection Registration
(2 answers)
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
How do I conduct the Dependency Injection in Integration Test?
Calling the departmentRepository or departmentAppService, is giving me null and error below.
public class DepartmentAppServiceTest
{
public SharedServicesContext context;
public IMapper mapper;
public IRepository<Department, int> departmentRepository;
public IDepartmentAppService departmentAppService;
public DepartmentAppServiceTest()
{
ServiceCollection services = new ServiceCollection();
services.AddTransient<IRepository<Department>, BaseRepository<Department>>();
services.AddTransient<IDepartmentAppService, DepartmentAppService>();
debugging and setting breakpoints, both calling this repository or app service are null,
new method
[Fact]
var departmentDto = await departmentAppService.GetDepartmentById(2);
Constructors for App Service
DepartmentAppService(departmentRepository, mapper)
DepartmentRepository(dbcontext)
Error:
Message: System.NullReferenceException : Object reference not set to
an instance of an object.

For our integration tests we programatically startup the application and use HttpClient to make calls against the API Endpoints. This way your app runs through the whole Startup process and dependency injection works like a charm.
Here is an Example of the Server Startup and client creation, it can be reused for multiple tests:
_server = new TestServer(new WebHostBuilder()
.UseEnvironment("Testing")
.UseContentRoot(applicationPath)
.UseConfiguration(new ConfigurationBuilder()
.SetBasePath(applicationPath)
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.Testing.json")
.Build()
)
.UseStartup<TestStartup>());
_client = _server.CreateClient();
// Act
var response = await _client.GetAsync("/");
// Assert
response.EnsureSuccessStatusCode();
It's also documented by microsoft like this with the HttpClient:
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2

If you use the departmentAppService local variable, that is null. Your object is in the container. You can retrieve that by calling the GetRequiredService or GetService method.
I used the ServiceCollection in a console app like this way.
IServiceCollection services = new ServiceCollection();
services.AddSingleton<IDepartmentAppService, DepartmentAppService>();
using (ServiceProvider serviceProvider = services.BuildServiceProvider())
{
var departmentAppService = serviceProvider.GetRequiredService<IDepartmentAppService>();
await departmentAppService.GetDepartmentById(2);
}
The thing which you should care, the test class is recreating for each test cases.

Using Moq you'll be able to fake the depedencies then pass them into your service. For example, your test method could look like:
//arrange
var company = new company() { company_name = "TCS" };
var mockRepo = new Mock<ICompany>();
mockRepo.Setup(x => x.InsertCompany(company)).Returns(true);
var companyObject = new Company(mockRepo.Object);
var retrnData = companyObject.InsertCompany(company)
This code snippet is taken from this article which I suggest you check out:
https://www.c-sharpcorner.com/UploadFile/dacca2/unit-test-using-mock-object-in-dependency-injection/

Related

Nunit 3: Test a Controller that uses IHttpClientFactory as Constructor Parameter

Update 20221024: I have used Ruikai Feng's solution in order to use Mockoon with my tests. I realize this is not a correct approach from a unit testing approach and am working to change my approach.
Update 20221019: I have been using moq to mock out the IHttpClientFactory. The reason why I wanted to instantiate it was to call mock apis created in a tool called Mockoon which replicates apis. I have been so far unable to call these APIs likely because I have not yet properly mocked the ihttpclientfactory. I appreciate all the feedback as the solution is still ongoing at this time.
I am using a .NET 6 Web API controller with IHttpClientFactory to perform external API calls. As such, I have the following constructor:
public MyController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
This works because in my Program.cs I add an HTTP Client to my builder.Services.
In my tests, how do I instantiate/set up the httpClientFactory for the controller because I need it to instantiate my controller: var controller = new MyController(httpClientFactory); generates an error since there isn't any settings added.
I ran into a similar issue with configurations from appsettings.json and resolved with ConfigurationBuilder but there doesn't seem to be a similar one for IHttpClientFactory.
If you need any more information, please let me know. Thanks!
In order to be able to use a properly mocked IHttpClientFactory in your unit test you need to do the following steps:
Setup a DelegatingHandler mock
var mockHandler = new Mock<DelegatingHandler>();
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
.Verifiable();
mockHandler.As<IDisposable>().Setup(s => s.Dispose());
This sample mock will always return with 200 OK status code and without a response body
Tailor the setup for your needs
Create an HttpClient
var httpClient = new HttpClient(mockHandler.Object);
It creates an HttpClient instance and pass the above handler to it
Setup an IHttpClientFactory mock
var mockFactory = new Mock<IHttpClientFactory>(MockBehavior.Strict);
mockFactory
.Setup(factory => factory.CreateClient())
.Returns(httpClient)
.Verifiable();
It setups an IHttpClientFactory mock to return the above HttpClient for the CreateClient method call
If you use the IHttpClientFactory to create a named client then change the Setup to this .Setup(factory => factory.CreateClient(It.IsAny<string>()))
Use the mock objects for verification
mockFactory.Verify(factory => factory.CreateClient(), Times.Once);
mockHandler.Protected()
.Verify("SendAsync", Times.Once(), It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>());
I tried as below:
[TestFixture]
public class IndexActionTests
{
private HomeController controller;
[SetUp]
public void Setup()
{
var services = new ServiceCollection();
services.AddHttpClient();
var provider = services.BuildServiceProvider();
var httpclientfactory = provider.GetService<IHttpClientFactory>();
controller = new HomeController(httpclientfactory);
}
[Test]
public void Test1()
{
var result = controller.Index();
Assert.AreEqual(typeof(ViewResult),result.GetType());
}
}
Result:

How to test a controller that uses IMemoryCache?

I have a controller with the definition:
public async Task<ResponseDto> MethodNameController(List<string> identifiers)
{
if(!_cache.TryGetValue(key, out IDictonary<string, string> result))
{
result = await service.GetMethodService(activityContextObject, identifiers)
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(80))
.SetAbsoluteExpiration(TimeSpan.FromSeconds(120))
.SetSize(1024);
_cache.Set(key, result, cacheEntryOptions);
}
return new ResponseDto{ //ResponseDto Object split into many fields};
}
The constructor is as below
public Controller(serviceName, httpContextAccessor, IOptionsSnapshot_config, IMemoryCache)
{
_serviceName = serviceName,
_httpContextAccessor = httpContextAccessor,
_config = IOptionsSnapshot_config
_cache = IMemoryCache
}
I'm facing difficulty in unit testing this method. I followed this blog, this SO answer and many more trynig to replicate them in my scenario and failed. I tried passing regular memory cache object(because I'm unable to mock it) but invoking controller returns error slidingExpirationTime should be positive, current time set is 00:00:00 I'm unable to set the sliding expiration in test classes.
Can anyone guide me to correct resources or tell me how I can test this method. I'm new to writing xUnit tests, so any help will be great(For learning moq etc).
The easiest would be to mock it using some libraries, like AutoFixture, Moq.
Generally you mock interfaces as follows:
var fixture = new Fixture() //creates objects that has fine logic in creating objects
.Customize(new AutoMoqCusotmization); // customize the fixture to automoq interfaces
var cacheMock = fixture.Create<Mock<IMemoryCache>>();
// use cacheMock.Setup method
another, simplier option would be to use directly Mock:
var cacheMock = new Mock<IMemoryCache>();
// use cacheMock.Setup method
If you can not use any of the above you can define dummy implmentation for the service, like:
internal class DummyMemoryCache : IMemoryCache
{
// implement interface
)
and use it in place of IMemoryCache.

Unit Test and IDistributedCache using azure redis

I have a working implementation of Azure Redis and .Net Core 2 using code very similar to what's described in this article
My question is, how do you instantiate an instance of the cache from a unit test class? I've looked through a number of resources and found nothing.
I need to be able to create an instance to instantiate a class such as
public CacheManager(IDataManager dataservices, IDistributedCache cache)
{
_cache = cache;
_dataservices = dataservices;
}
The code in startup.cs uses ConfigureServices
//Configure Redis Cache
var redisconnection = Configuration.GetConnectionString("Redis");
services.AddDistributedRedisCache(o => { o.Configuration = redisconnection; });
Maybe I need to add a package to the unit test project? How is this done?
I have used the Microsoft.Extensions.Caching.Distributed.MemoryDistributedCache class for unit testing. This is an in-memory implementation of IDistributedCache.
Here is a snippet of my unit testing code.
[TestMethod]
public void ExampleTestMethod()
{
var expectedData = new byte[] { 100, 200 };
var opts = Options.Create<MemoryDistributedCacheOptions>(new MemoryDistributedCacheOptions());
IDistributedCache cache1 = new MemoryDistributedCache(opts);
cache1.Set("key1", expectedData);
var cachedData = cache1.Get("key1");
Assert.AreEqual(expectedData, cachedData);
//Use the variable cache as an input to any class which expects IDistributedCache
}
In my example, I am on .NET Core 3.1 and the relevant NUGET packages are
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.1.4" />
You could just mock the interfaces to behave as needed for the isolated unit test.
public void Test_CacheManager() {
//Arrange
IDataManager dataservices = new Mock<IDataManager>();
IDistributedCache cache = new Mock<IDistributedCache>();
var subject = new CacheManager(dataservices.Object, cache.Object);
//Setup the mocks to behave as expected.
//Act
//...call the method under test
//Assert
//...assert the expected behavior
}
The above example uses Moq in order to demonstrate how to mock instances of the dependencies of the class under test.
Reference Moq Quickstart to get a better understanding of how to use the mocking library.
If you are connecting to an actual redis connection then this will no longer be a unit test but an integration test, which would require a completely different approach.
public void Test_CacheManager() {
//Arrange
IDataManager dataservices = new Mock<IDataManager>();
//Setup the mocks to behave as expected.
//Configure Redis Cache
var services = new ServiceCollection();
var redisconnection = "...";
services.AddDistributedRedisCache(o => { o.Configuration = redisconnection; });
var provider = services.BuildServiceProvider();
IDistributedCache cache = provider.GetService<IDistributedCache>();
var subject = new CacheManager(dataservices.Object, cache);
//Act
//...call the method under test
//Assert
//...assert the expected behavior
}
This how i managed to do that in .net core 2.0 and 3.1.
You need to use MemoryDistributedCache. And pass it through your service constructor. Your service in a real word uses IDistributedCache by depedency injection. MemoryDistributedCache also implements IDistributedCache.
var mockedCacheSettings = new Mock<IOptions<CacheSettings>>();
var options = new OptionsWrapper<MemoryDistributedCacheOptions>(new MemoryDistributedCacheOptions());
_memoryDistributedCache = new MemoryDistributedCache(options);
_distributedCacheService = new DistributedCacheService(_memoryDistributedCache, mockedCacheSettings.Object, NullLogger<DistributedCacheService>.Instance);
i needed DistributedCache for test a service so i wrote these code:
private IDistributedCache BuildDistributedCash()
{
var opt = Options.Create(new MemoryDistributedCacheOptions());
return new MemoryDistributedCache(opt);
}
[Fact]
public async Task CheckStatusTest()
{
var buildDistributedCash= BuildDistributedCash();
var authService = new AuthService(buildDistributedCash);
var userName = "test.z#gmail.com";
bool result = await authService.CheckStatus(userName);
Assert.True(result);
}

Structure Map - Replace Interface with mock object at runtime

I am doing some integration tests for my OWIN based Web API. I am using structure map as DI container. In one of the cases, I need to mock out an API call ( can't include it as part of the test).
How would I go about doing this using Structure Map? I have done it using SimpleInjector but the code base I am working on is using Structure Map and I can't figure out how I would do this.
Solution with SimpleInjector:
Startup.cs
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
app.UseWebApi(WebApiConfig.Register(config));
// Register IOC containers
IOCConfig.RegisterServices(config);
}
ICOCConfig:
public static Container Container { get; set; }
public static void RegisterServices(HttpConfiguration config)
{
Container = new Container();
// Register
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(Container);
}
And in my Integration test, I mock out the interface that calls the other API.
private TestServer testServer;
private Mock<IShopApiHelper> apiHelper;
[TestInitialize]
public void Intitialize()
{
testServer= TestServer.Create<Startup>();
apiHelper= new Mock<IShopApiHelper>();
}
[TestMethod]
public async Task Create_Test()
{
//Arrange
apiHelper.Setup(x => x.CreateClientAsync())
.Returns(Task.FromResult(true);
IOCConfig.Container.Options.AllowOverridingRegistrations = true;
IOCConfig.Container.Register<IShopApiHelper>(() => apiHelper.Object, Lifestyle.Transient);
//Act
var response = await testServer.HttpClient.PostAsJsonAsync("/api/clients", CreateObject());
//Assert
Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
}
I found this in the structure-map documentation but it doesn't allow me to inject a mock object in there (only types).
How I can inject a mock version of IShopApiHelper (Mock) when running my integration tests? (I am using the Moq library for mocking)
Assuming the same API structure as in the original example you can do basically the same thing as demonstrated in the linked documentation.
[TestMethod]
public async Task Create_Test() {
//Arrange
apiHelper.Setup(x => x.CreateClientAsync())
.Returns(Task.FromResult(true);
// Use the Inject method that's just syntactical
// sugar for replacing the default of one type at a time
IOCConfig.Container.Inject<IShopApiHelper>(() => apiHelper.Object);
//Act
var response = await testServer.HttpClient.PostAsJsonAsync("/api/clients", CreateObject());
//Assert
Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
}

Transitioning to AutofacWebApiDependencyResolver from MVC's DependencyResolver - Where is .Current?

I had AutoFac working properly with MVC4. I'm trying to transition to Web API 2. Here's what I've got for setting up AutoFac:
public class AutofacRegistrations
{
public static void RegisterAndSetResolver()
{
// Create the container builder.
var containerBuilder = new ContainerBuilder();
// Register the Web API controllers.
containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Only generate one SessionFactory ever because it is expensive.
containerBuilder.Register(x => new NHibernateConfiguration().Configure().BuildSessionFactory()).SingleInstance();
// Everything else wants an instance of Session per HTTP request, so indicate that:
containerBuilder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerApiRequest();
containerBuilder.Register(x => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).InstancePerApiRequest();
containerBuilder.RegisterType<NHibernateDaoFactory>().As<IDaoFactory>().InstancePerApiRequest();
containerBuilder.RegisterType<StreamusManagerFactory>().As<IManagerFactory>().InstancePerApiRequest();
// Build the container.
ILifetimeScope container = containerBuilder.Build();
// Create the depenedency resolver.
var dependencyResolver = new AutofacWebApiDependencyResolver(container);
// Configure Web API with the dependency resolver.
GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
}
}
I'm pretty confident all of that is correct. My problem arises when I'm trying to setup some test cases. My base class for my test cases isn't a controller so it isn't automatically passed anything. In MVC4 I did the following:
[SetUp]
public void SetUp()
{
HttpSimulator = new HttpSimulator().SimulateRequest();
Logger = DependencyResolver.Current.GetService<ILog>();
DaoFactory = DependencyResolver.Current.GetService<IDaoFactory>();
Session = DependencyResolver.Current.GetService<ISession>();
ManagerFactory = DependencyResolver.Current.GetService<IManagerFactory>();
}
[TearDown]
public void TearDown()
{
HttpSimulator.Dispose();
}
Unfortunately, there's no DependencyResolver.Current in WebAPI. So I'm left wondering how to do this properly?
This builds, but is NOT correct. I received the message "Session Closed!" when I try to execute a test case:
[SetUp]
public void SetUp()
{
using (var scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
// TODO: Consider initializing Helpers during setup to keep this DRY.
Logger = (ILog)scope.GetService(typeof(ILog));
DaoFactory = (IDaoFactory)scope.GetService(typeof(IDaoFactory));
Session = (ISession)scope.GetService(typeof(ISession));
ManagerFactory = (IManagerFactory)scope.GetService(typeof(IManagerFactory));
}
}
With WebAPI, you don't need access to the current resolver because the current dependency scope generally comes along with the inbound HttpRequestMessage. That message is also what's responsible for generating the new request scope.
You can see the code for this in the System.Net.Http.HttpRequestMessageExtensions.GetDependencyScope method.
One big thing you'll notice in WebAPI is that you don't actually need to set anything in global static values - that is, you don't need to set a global configuration/resolver because everything is instance-based now.
For testing, what this means is:
Your setup will create an HttpRequestMessage with the appropriate dependency resolver and configuration.
Your teardown will dispose of the HttpRequestMessage which will, in turn, dispose the dependency scopes, etc. down the line.
Individual tests will use HttpRequestMessage.GetDependencyScope() if they need to do manual resolution of something and the request message will be used to coordinate/pass around the scope.
In a more concrete fashion, it might look like:
private HttpRequestMessage _request;
[SetUp]
public void SetUp()
{
var builder = new ContainerBuilder();
// Register stuff.
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
var config = new HttpConfiguration();
config.DependencyResolver = resolver;
config.EnsureInitialized();
this._request = new HttpRequestMessage();
this._request.SetConfiguration(config);
}
[TearDown]
public void TearDown()
{
this._request.Dispose();
}
[Test]
public void Test()
{
// When you need to resolve something, use the request message
this._request.GetDependencyScope().GetService(typeof(TheThing));
}
What's nice about this is that you don't have to fight with global configuration settings or resetting static values after every test.
You might wonder why you'd pass around the whole request message rather than just the dependency resolver - the reason is that the request message is what coordinates and controls the lifetime of the dependency scope. Otherwise, when you call GetDependencyScope multiple times, you'll get multiple different scopes rather than the same one as you'd expect.
Some things to consider from a design perspective:
You might want to put the actual registrations of things into an Autofac module so it can be reused in both tests and in your RegisterAndSetResolver method without having to worry about global statics getting tampered with.
Instead of a RegisterAndSetResolver modifying the global static configuration, you might consider just setting the resolver on the HttpConfiguration object that gets wired up in that WebApiConfig.Register method that WebAPI gives you. Take an HttpConfiguration object in as a parameter and set the resolver on that rather than the global.
If you're doing every registration for everything in a unit test, your unit tests might be closer to "integration tests." You might consider looking at only what's required for the stuff you're testing and using a mock framework to register stubs rather than actually registering a boatload of "real stuff."
Anyway, HttpRequestMessage is the way to go for WebAPI.

Categories