Unit Test and IDistributedCache using azure redis - c#

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);
}

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:

Unit test the Get() Method using xUnit web api

Does any one know how to write a unit test (using xUnit) for the following Get() Method?
Get() method is in the controller and returns list of all Categories:
public class CategoryController : Controller
{
private MyContext x;
public CategoryController(MyContext y)
{
x = y;
}
[HttpGet]
public ActionResult<IEnumerable<Category>> Get()
{
return x.Categories.ToList();
}
}
If you are using EFCore as ORM, you can use InMemory database for unit testing.
There simple example:
[Fact]
public void TestGet()
{
_options = new DbContextOptionsBuilder<MyContext>()
.UseInMemoryDatabase(databaseName: "default")
.Options;
var context = new MyContext(_options);
context.EnsureSeed();
var controller = new CategoryController(context);
//Act
var results = controller.Get();
//Assert
Assert.NotNull(results);
Assert.True(results.Count > 0, "Expected to be greater than 0.");
}
Also you need implement EnsureSeed method. Example:
public static void EnsureSeed(this MyContext dataContext)
{
//Check if database is created, if not - create
dataContext.Database.EnsureCreated();
var category = new Category()
{
Id = 1
};
dataContext.Categories.Add(category);
dataContext.SaveChanges();
}
From what I've seen and read the best way to unit test a controller function is to create an instance of the server host from your test setup and make requests directly to your endpoint - this will allow you test the transport layer of your application like the API contract and Http protocols.
The following is an example implemented in .Net Core:
[Trait]
public class CategoryControllerTests : IClassFixture<WebApplicationFactory<Startup>>
{
// Startup - the entry point of most .net core project
private readonly WebApplicationFactory<Startup> _factory;
public CategoryControllerTests(WebApplicationFactory<Startup> factory)
{
// Any webhost config needed to run tests against the test
_factory = factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
// register any mock dependancies there - any dependencies in Startup.cs will hold unless overridden by a mock
services.AddScoped(x => new Mock() );
});
});
}
[Fact]
public async Task Get_ValidRequest_ReturnsData()
{
var client = _factory.CreateClient();
// Whatever routing protocol you use to define your endpoints
var url = "/category";
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsAsync<List<Category>>();
// Any asserts on your response
Assert.NotNull(content);
}
}
This is dependant on how you have setup the startup/initialisation of your project, it will allow you to test the project as though it were running in a production environment while letting you mock out any dependancies below the transport layer for a true unit test.
Note: the use of IClassFixture<WebApplicationFactory> - this will let you reuse an instance of WebApplicationFactory<Startup> for faster test execution; XUnit will inject this for you as part of the framework.

Net Core: Dependency Injection in Integration Test [duplicate]

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/

Unit Testing Controller with Authorization ASP.NET Core 2.0 Web API

I have a controller:
public class InvitationsController: Controller {
private readonly IMapper _mapper;
private readonly IInvitationManager _invitationManager;
private readonly UserManager<MyAppUser> _userManager;
public InvitationsController(
IInvitationManager invitationManager,
IMapper mapper,
UserManager<MyAppUser> userManager,
IJobManager jobManager
) {
_invitationManager = invitationManager;
_mapper = mapper;
_userManager = userManager;
}
[Authorization]
GetInvitationByCode(string code) { ... }
I'm trying to write unit tests using Xunit and Moq. Here is the implentation of my test:
public class InvitationsControllerTests {
private Mock<IInvitationManager> invitationManagerMock;
private Mock<UserManager<MyAppUser>> userManagerMock;
private Mock<IMapper> mapperMock;
private InvitationsController controller;
public InvitationsControllerTests() {
invitationManagerMock = new Mock<IInvitationManager>();
userManagerMock = new Mock<UserManager<MyAppUser>>();
mapperMock = new Mock<IMapper>();
controller = new InvitationsController(invitationManagerMock.Object,
mapperMock.Object,
userManagerMock.Object);
}
[Fact]
public async Task GetInvitationByCode_ReturnsInvitation() {
var mockInvitation = new Invitation {
StoreId = 1,
InviteCode = "123abc",
};
invitationManagerMock.Setup(repo =>
repo.GetInvitationByCodeAsync("123abc"))
.Returns(Task.FromResult(mockInvitation));
var result = await controller.GetInvitationByCode("123abc");
Assert.Equal(mockInvitation, result);
}
I don't think I'm using the mocking functionality correctly. Specifically with UserManager. I can't find a clear answer on using Moq to test controllers protected by [Authorize]. When running my tests, it throws an exception on
controller = new InvitationsController(invitationManagerMock.Object,
mapperMock.Object,
userManagerMock.Object);
Which reads:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException: 'Can not instantiate proxy of class: Microsoft.AspNetCore.Identity.UserManager`1[[MyApp.api.Core.Models.MyAppUser, MyApp.api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
Could not find a parameterless constructor.'
You're not unit testing; you're integration testing. When you find yourself setting up ten thousand mocks just to run a method, that's a pretty good sign it's an integration test. Additionally, things like authorization only happen as part of the request lifecycle; there's no way to test that, without doing an actual request, which again, means you're integration testing.
As such, use the test host.
private readonly TestServer _server;
private readonly HttpClient _client;
public MyTestClass()
{
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[Fact]
public async Task GetInvitationByCode_ReturnsInvitation() {
var mockInvitation = new Invitation {
StoreId = 1,
InviteCode = "123abc",
};
var response = await _client.GetAsync("/route");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<Invitation>(responseString);
// Compare individual properties you care about.
// Comparing the full objects will fail because of reference inequality
Assert.Equal(mockInvitation.StoreId, result.StoreId);
}
If you need to scaffold your data to make the correct result return, simply use the in-memory database provider. The easiest way to use this for integration testing is to specify a new environment like "Test". Then, in your startup, when configuring your context, branch on the environment and use the in-memory provider (instead of SQL Server or whatever) when the environment is "Test". Then, when setting up your test server for integration testing, simply add .UseEnvironment("Test") before .UseStartup<Startup>().
I think, problem is in dependency injection. In your Startups.cs file you could find similar string: services.AddIdentity<AppUser, AppRole>().AddEntityFrameworkStores<AppDbContext>().AddDefaultTokenProviders(); it means that magic of namespace Microsoft.Extensions.DependencyInjection provide you an instance of your User- or RoleManger anywhere where you want to use it. For example, in InvitationsController using injectin in constructor.
You can try inject UserManger in test class and mock it. Or read similar question

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);
}

Categories