I am trying to test the Exception handler in my application.
However I can't generate an Exception for the Constructor.
Normally, I would create a moq of an Object and then do a setup where a call to Object.method throws an Exception. Then simply detect the Exception in the Test.
However, in this Constructor the only call is:
CredentialProfileStoreChain.TryGetAWSCredentials
CredentialProfileStoreChain.TryGetAWSCredentials can't be overridden so I can't use moq Setup to generate an Exception.
Code:
public class AWSDynamoDbManager : IAWSDynamoDbManager
{
private readonly ILogger _logger;
private readonly AmazonDynamoDBClient _dynamoDbClient;
//NOTE: This setting is in the app.config of the calling application so that different uses can use different profiles
private readonly string _awsProfileName = ConfigurationManager.AppSettings["AWSProfileName"];
public AWSDynamoDbManager(CredentialProfileStoreChain chain, ILogger logger)
{
this._logger = logger;
try
{
AWSCredentials awsCredentials;
chain.TryGetAWSCredentials(_awsProfileName, out awsCredentials);
_dynamoDbClient = new AmazonDynamoDBClient(awsCredentials, RegionEndpoint.EUWest2);
}
catch (Exception e)
{
logger.Error("Could Not Open DynamoDB");
logger.Error("Error: " + e.Message);
throw;
}
}
}
Test:
public void TestToSeeIfWeCatchTheExceptionIfWeCannotConnectToTheDatabase()
{
// arrange
var mockLogger = new Mock<ILogger>();
var mockChain = new Mock<CredentialProfileStoreChain>();
// act / assert
Assert.Catch<ArgumentException>(() => new AWSDynamoDbManager(mockChain.Object, mockLogger.Object));
}
What can I use to force the Constructor to cause an Exception?
when my hands are tied because of an external dependency or static type, i use a wrapper, so that's what i'd use here. since we can't mock a CredentialProfileStoreChain, we throw it in a wrapper and use the wrapper.
public interface ICredentialProfileStoreChainWrapper
{
void TryGetAWSCredentials(/*TODO*/);
}
public class CredentialProfileStoreChainWrapper
{
readonly CredentialProfileStoreChain _Chain;
public CredentialProfileStoreChainWrapper(CredentialProfileStoreChain chain)
{
_Chain = chain;
}
public void TryGetAWSCredentials(/*TODO*/)
{
_Chain.TryGetAWSCredentials(/*TODO*/);
}
}
public class AWSDynamoDbManager : IAWSDynamoDbManager
{
public AWSDynamoDbManager(ICredentialProfileStoreChainWrapper chainWrapper, ILogger logger)
{
//TODO
chainWrapper.TryGetAWSCredentials(/*TODO*/);
}
}
public class Tests
{
[Test]
public void TestToSeeIfWeCatchTheExceptionIfWeCannotConnectToTheDatabase()
{
var wrapper = new Mock<ICredentialProfileStoreChainWrapper>();
var logger = new Mock<ILogger>();
var manager = new AWSDynamoDbManager(wrapper.Object, logger.Object);
wrapper.Setup(s => s.TryGetAWSCredentials(/*TODO*/)).Throws(new Exception());
//TODO
}
}
Related
I have a class with a logging method that I want to test. For the example I want to check if the Console.WriteLine method has been called. This is my sample class
public class MyClass
{
public void LogSomething()
{
Console.WriteLine("Test");
}
}
and its test
public class MyClassTests
{
[Fact]
public void LogsSomething()
{
MyClass myClass = new MyClass();
myClass.LogSomething(); // Assert that Console.WriteLine has been called once
}
}
Is there something I can use? (Preferably without additional packages)
I am looking for assertions like this (Pseudo code)
Assert.Method(Console.WriteLine).ToHaveBeenCalledWith(myClass.LogSomething);
Assert.Method(Console.WriteLine).ToHaveBeenCalledWith(myClass.LogSomething).Times(3); // Check if Console.WriteLine has been called 3 times (loop inside the LogSomething method)
I think you cannot assert that out of the box.
Your best bet is using Moq or another mock framework to do something along this lines.
You should always aim for a decoupled logic using dependency injection, otherwise you will end up having a tightly coupled code that is difficult to test and will not be easy to refactor whenever a change in requirements arrives
public interface ILogger
{
public void Log();
}
public class Logger: ILogger
{
public void Log()
{
Console.WriteLine("Look mom, i'm logging");
}
}
public class MyClass
{
private readonly ILogger Logger
public MyClass(ILogger logger)
{
Logger = logger;
}
public void MyMethod()
{
//other code
Logger.Log();
}
}
public class MyClassTests
{
[Fact]
public void LogsSomething()
{
//arrange
var logger = new Mock<ILogger>();
//act
var sut = new MyClass(logger.Object);
sut.MyMethod();
//Assert
logger.Verify(foo => foo.Log(), Times.Once()); //here
//some other assertions
}
}
Goal:
Fundamentally I am trying to add a background job, that has dependencies injected, to a console application.
Problem:
Although the jobs are queued, they are never executed.
Program.cs
var appSettings = ConfigHelper.GetConfig();
Console.WriteLine("Initialising Hangfire Server...");
GlobalConfiguration.Configuration.UseSqlServerStorage(appSettings.ConnectionString);
using (var server = new BackgroundJobServer())
{
Console.WriteLine("Hangfire Server started.");
var t = serviceProvider.GetService<ITestService>();
t.Test();
Console.ReadKey();
}
ServiceProviderFactory.cs
public static void Setup()
{
IServiceCollection services = new ServiceCollection();
...
services.AddDbContext<Db>(x => x.UseSqlServer(appSettings.ConnectionString));
services.AddTransient<IInsertLogJob, InsertLogJob>();
services.AddTransient<ITestService, TestService>();
_serviceProvider = services.BuildServiceProvider();
}
TestService.cs
public interface ITestService
{
void Test();
}
public class TestService : ITestService
{
private readonly ILogger<TestService> _logger;
public TestService(ILogger<TestService> logger)
{
_logger = logger;
}
public void Test()
{
logger.LogInformation("Test");
_logger.LogError("Error");
}
}
Logger.cs
public class Logger : ILogger
{
...
Log log = new Log()
{
Message = message,
EventId = eventId.Id,
ObjectId = eventId.Name,
LogLevel = logLevel.ToString(),
CreatedTime = DateTime.Now
};
BackgroundJob.Enqueue<IInsertLogJob>(j => j.Insert(log));
}
InsertLogJob.cs
public interface IInsertLogJob
{
void Insert(Log log);
}
public class InsertLogJob : IInsertLogJob
{
private Db _dataContext;
public InsertLogJob(Db context)
{
_dataContext = context;
}
public void Insert(Log log)//<-- this never happens
{
_dataContext.Logs.Add(log);
_dataContext.SaveChanges();
}
}
DB Record
So all the code up to the point where the data has to be inserted into the database runs, the Hangfire job gets inserted as per the picture above, but the code is never executed.
I have a class level ILogger which is set up with the ILoggerFactory in the constructor. The logger is then used within a method within that class and this works perfectly.
I am struggling on how to Mock the ILogger and ILoggerFactory so I can unit test the LogError message. Can anyone show me an example of this?
I am using xUnit and Microsoft.Extentions.Logging for the loggin
//This is my unit test project
[Fact]
public void TestLogErrorMessage()
{
MyClass myClass = new MyClass (MockLoggerFactory().Object);
var result = myClass.Mymethod("a")
//How do I test the LogError message???
}
//Not sure if this is correct
private Mock<ILoggerFactory> MockLoggerFactory()
{
Mock<ILoggerFactory> mockLoggerFactory = new
Mock<ILoggerFactory>(MockBehavior.Default);
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>()))
.Returns(MockLogger().Object);
return mockLoggerFactory;
}
private Mock<ILogger> MockLogger()
{
var logger = new Mock<ILogger>();
return logger;
}
//This is the class/method i need to test
private readonly ILogger logger;
public MyClass(ILoggerFactory loggerFactory)
{
if (loggerFactory != null)
{
this.logger = loggerFactory.CreateLogger<MyClass>();
}
}
public string Mymethod(string msg)
{
if(msg = "a")
{
this.logger.LogError($"error");
}
return "a string";
}
This is what finally worked for me, successful verification of LogError call:
var loggerMock = new Mock<ILogger>();
Expression<Action<ILogger>> logAction = x =>
// You can change this up with other severity levels:
x.Log<It.IsAnyType>(LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>());
loggerMock.Setup(logAction).Verifiable();
// Call a method that calls LogError here.
loggerMock.Object.LogError("test");
loggerMock.Verify(logAction, Times.Once);
You could do something like this
(note: this does not work in this specific case because LogError is an extension method, see below for an update):
Mock<ILogger> _logger; // declare it somewhere where your test can access it
[Fact]
public void TestLogErrorMessage()
{
MyClass myClass = new MyClass(MockLoggerFactory().Object);
var result = myClass.Mymethod("a")
_logger.Verify();
}
private Mock<ILoggerFactory> MockLoggerFactory()
{
_logger = new Mock<ILogger>();
_logger.Setup(log => log.LogError(It.IsAny<string>())).Verifiable();
Mock<ILoggerFactory> mockLoggerFactory = new Mock<ILoggerFactory>(MockBehavior.Default);
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>()))
.Returns(_logger.Object);
return mockLoggerFactory;
}
The key thing to note is the call to Verifiable() after setting up the ILogger mock. You can read a bit more about Verifiable() in this SO question. After your test ran, you can check whether the method was called by calling .Verify() on the mock.
Depending on your needs, you could set this up in the constructor of your test class (if you need it for all/most tests) or directly inside your test method. You could also return it alongside the ILoggerFactory. The point is to hold onto the logger so you can verify against it that the method was called.
For your specific case (trying to verify calls to ILogger.LogError) you must not mock LogError, but the underlying method ILogger.Log. That could look like this:
var formatter = new Func<It.IsAnyType, Exception, string>((a, b) => "");
m.Setup(x => x.Log<It.IsAnyType>(LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
formatter))
.Verifiable();
Another alternative would be to make a fake implementation of ILogger and return that from the Mock<ILoggerFactory>:
mockLoggerFactory.Setup(_ => _.CreateLogger(It.IsAny<string>())
.Returns(new FakeLogger());
public class FakeLogger : ILogger
{
public static bool LogErrorCalled { get; set; }
public IDisposable BeginScope<TState>(TState state)
{
throw new NotImplementedException();
}
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if(logLevel == LogLevel.Error)
{
LogErrorCalled = true;
}
}
}
And then after your test you can check whether FakeLogger.LogErrorCalled is true. This is simplified for your specific test - you can get more elaborate than this of course.
Currently I'm able to handle IServiceCollection to inject mocks for particular services in the following manner.
public class TestClass
{
private IMediator _mediatr;
private void SetupProvider(IUnitOfWork unitOfWork, ILogger logger)
{
configuration = new ConfigurationBuilder().Build();
_services = new ServiceCollection();
_services.AddSingleton(configuration);
_services.AddScoped(x => unitOfWork);
_services.AddSingleton(logger);
_services.AddMediatR(Assembly.Load("Application"));
_services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggerBehaviour<,>));
_mediator = _services.BuildServiceProvider().GetService<IMediator>();
}
[Fact]
public async void UnitTest_Success()
{
var unitOfWork = new Mock<IUnitOfWork>();
var logger = new Mock<ILogger>();
SetupProvider(unitOfWork.Object, logger.Object);
var fixture = new Fixture();
var command = fixture.Create<MediatorCommand>();
unitOfWork.Setup(x => x.Repository.FindAll(It.IsAny<IList<long>>(), It.IsAny<bool?>()))
.ReturnsAsync(new List<Domain.Model>());
var response = await _mediatr.Send(command);
using (new AssertionScope())
{
response.Should().NotBeNull();
response.IsSuccess.Should().BeTrue();
}
}
}
For the following subject under test
public class MediatorCommand : IRequest<CommandResponse>
{
public string Name { get; set ;}
public string Address { get; set; }
}
public class MediatorCommandHandler : IRequestHandler<MediatorCommand, CommandResponse>
{
private readonly ILogger _logger;
private readonly IUnitOfWork _unitOfWork;
public MediatorCommandHandler(IUnitOfWork unitOfWork, ILogger logger)
{
_logger = logger;
_unitOfWork = unitOfWork;
}
public async Task<CommandResponse> Handle(MediatorCommand command, CancellationToken cancellationToken)
{
var result = new CommandResponse { IsSuccess = false };
try
{
var entity = GetEntityFromCommand(command);
await _unitOfWork.Save(entity);
result.IsSuccess = true;
}
catch(Exception ex)
{
_logger.LogError(ex, ex.Message);
}
return result;
}
}
This test runs fine and the unitOfWork and logger mocks are used in the command handlers.
I'm try to move this so that the IServiceCollection construction happens per class instead of each test using the following:
public class SetupFixture : IDisposable
{
public IServiceCollection _services;
public IMediator Mediator { get; private set; }
public Mock<IUnitOfWork> UnitOfWork { get; private set; }
public SetupFixtureBase()
{
UnitOfWork = new Mock<IUnitOfWork>();
configuration = new ConfigurationBuilder().Build();
_services = new ServiceCollection();
_services.AddSingleton(configuration);
_services.AddScoped(x => UnitOfWork);
_services.AddSingleton(new Mock<ILogger>().Object);
_services.AddMediatR(Assembly.Load("Application"));
_services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggerBehaviour<,>));
Mediator = _services.BuildServiceProvider().GetService<IMediator>();
}
public void Dispose()
{
Mediator = null;
_services.Clear();
_services = null;
}
}
public class TestClass : IClassFixture<SetupFixture>
{
protected readonly SetupFixture _setupFixture;
public UnitTestBase(SetupFixture setupFixture)
{
_setupFixture = setupFixture;
}
[Fact]
public async void UnitTest_Success()
{
var fixture = new Fixture();
var command = fixture.Create<MediatorCommand>();
_setupFixture.UnitOfWork.Setup(x => x.Repository.FindAll(It.IsAny<IList<long>>(), It.IsAny<bool?>()))
.ReturnsAsync(new List<Domain.Model>());
var response = await _mediatr.Send(command);
using (new AssertionScope())
{
response.Should().NotBeNull();
response.IsSuccess.Should().BeTrue();
}
}
}
Unfortunately with this method my mocks do not get injected on the command handler. Is there a way to get this to work?
Thank you,
I found the issue and it is not related to moving to IClassFixuture<>. The issue was that I was initializing Mediator on a base class an then adding the mock UnitOfWork on a derived class.
This cause the Mediator initialization to fail because one of the beheviours expected the UnitOfWork which at the time was not yet on the container.
Moving the initialization of Mediator after all the services have been added helped me resolve the issue and now all works as expected.
If you try the same thing, please make sure to include all the services in the container before initializing any objects that require those dependencies.
Thank you all those who had input.
I have created small kind of xunit test case but I don't know how to create this controller which i have mention below.
public class PropertyController : ControllerBase
{
private readonly IMediator _mediator;
private readonly ILogger<PropertyController> _logger;
public PropertyController(IMediator mediator, ILogger<PropertyController> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<IActionResult> AddProperty([FromBody] AddPropertyCommand command)
{
bool commandResult = false;
_logger.LogInformation(
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({#Command})",
command.GetGenericTypeName(),
nameof(command.ModifiedUserId),
command.ModifiedUserId,
command);
commandResult = await _mediator.Send(command);
if (!commandResult)
{
return BadRequest();
}
return Ok();
}
I have created like this. i have mock the dependency and create a test case for add command is working fine or not
public class PropertyControllerTest
{
private readonly PropertyController _it;
private readonly Mock<IMediator> _mediatorMock;
private readonly Mock<ILogger<PropertyController>> _loggerPropertycontrollerMock;
public PropertyControllerTest()
{
_mediatorMock = new Mock<IMediator>();
_loggerPropertycontrollerMock = new Mock<ILogger<PropertyController>>();
_it = new PropertyController(_mediatorMock.Object, _loggerPropertycontrollerMock.Object);
}
[Fact]
public void it_Should_add_information_successfully_and_returns_200_status_result()
{
//How can i write xunit test case. I'm creating like this
_mediatorMock.Setup(x => x.Send().Returns(property);
}
The test below covers the 200 status result - a similar test for bad requests would be very similar.
[Fact]
public void it_Should_add_information_successfully_and_returns_200_status_result()
{
// Arrange
var expected = new AddPropertyCommand();
_mediatorMock.Setup(x => x.Send(It.IsAny<AddPropertyCommand>())).Returns(true);
// Act
var actionResult = _it.AddProperty(expected);
// Assert
actionResult.ShouldBeAssignableTo<OkResult>();
_mediatorMock.Verify(x => x.Send(expected));
}
N.B. actionResult.ShouldBeAssignableTo<OkResult>(); is written using the Shouldly assertion framework, you can swap that out for anything you like. The one built into XUnit would be like this: Assert.IsType(typeof(OkResult), actionResult);