Hi I am trying to unit test the following and check that this switch/case statement works:
DiagnosticsComponentFactory class
private readonly IServiceProvider _serviceCollection;
public IComponent Create (string name)
{
switch (name)
{
case BoardItemComponent.TypeName:
return _serviceCollection.GetService<BoardItemComponent>();
default:
throw new NotSupportedException();
}
}
My BoardItemComponent class:
public class BoardItemComponent
{
public const string TypeName = "name";
public BoardItemComponent(IConfigurationRepository configurationRepository) : base(configurationRepository)
{
}
}
BoardItemComponent is derived from IComponent, and it's added like follows in my Startup.cs file:
services.AddScoped<IComponent, BoardItemComponent>();
my unit test:
[Test]
public void GetComponent_GivenComponentFactory_ExpectBoardComponent()
{
var serviceCollection = new ServiceCollection();
ComponentFactoryRegistration.Register(serviceCollection);
var factory = new DiagnosticsComponentFactory(serviceCollection.BuildServiceProvider());
var component = factory.Create("name");
Assert.IsNotNull(component);
}
When I debug my unit test, component is null, despite it following all the correct steps. It goes into the switch case statement correctly and recognizes that is the correct case, however it still returns null.
From what I have shared (and apologies, as I know that the names in these code snippets are vague without context), is there any obvious reason that my unit test fails? I'm new when it comes to unit testing in C#.
Based on your comments you indicated that the component is registered as
services.AddScoped<IComponent, BoardItemComponent>();
The provider is aware of the IComponent interface, but is asking for BoardItemComponent implementation
_serviceCollection.GetService<BoardItemComponent>();
The above will return null if the provider is unaware how to resolve BoardItemComponent when explicitly requested.
Register the implementation
services.AddScoped<BoardItemComponent>();
and you can also associate it with the abstraction using the factory delegate
services.AddScoped<IComponent>(sp => sp.GetRequiredService<BoardItemComponent>());
Isolated testing should now be able to be done accordingly
[Test]
public void GetComponent_GivenComponentFactory_ExpectBoardComponent() {
//Arrange
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<BoardItemComponent>();
serviceCollection.AddScoped<IConfigurationRepository>(sp => Mock.Of<IConfigurationRepository>());
var factory = new DiagnosticsComponentFactory(serviceCollection.BuildServiceProvider());
//Act
var component = factory.Create(BoardItemComponent.TypeName);
//Assert
Assert.IsNotNull(component);
}
Now it was indicated that there may be more implementation in the future.
Lets say for example
services.AddScoped<BoardItemComponent>();
services.AddScoped<AnotherItemComponent>();
The factory can then be refactored
public class DiagnosticsComponentFactory {
private readonly IServiceProvider services;
public DiagnosticsComponentFactory (IServiceProvider services) {
this.services = services;
}
public IComponent Create (string name) {
switch (name) {
case BoardItemComponent.TypeName:
return services.GetRequiredService<BoardItemComponent>();
case AnotherItemComponent.TypeName:
return services.GetRequiredService<AnotherItemComponent>();
default:
throw new NotSupportedException();
}
}
}
Related
I have a repository with the following method DoSomeWork:
internal class MyRepository : IMyRepository
{
public MyRepository(ILogger<MyRepository> logger, IDbContextWrapper dbContext)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
}
public Task<Result> DoSomeWork(int someInt)
{
return Task.Run(() =>
{
try
{
var parameters = new DynamicParameters(new { SomeIntValue = someInt });
parameters.Add("WorkComplete", DbType.Boolean, direction: ParameterDirection.ReturnValue);
dbContext.TransactionedExecute("NameOfStoredProcedure", parameters, CommandType.StoredProcedure); //This is a wrapper for Dapper (DbConnection)
var status = (DoSomeWorkStatus)parameters.Get<int>("WorkComplete");
var workComplete = status == DoSomeWorkStatus.DoneSuccessfully;
return workComplete ? Result.WorkDone : Result.NoWorkDone;
}
catch(DatabaseTimeoutException dte)
{
logger.LogInformation(dte, "");
return Result.Error;
}
catch(DatabaseDeadlockException dde)
{
logger.LogInformation(dde, "");
return Result.Error;
}
});
}
}
What I'm trying to achieve is to test and verify that once a DatabaseTimeoutException or DatabaseDeadlockException is caught inside the try/catch, the task should return Result.Error. And all this should happen in one step (without retry).
In the test I have the following:
private Mock<IMyRepository> myRepoMock;
private MyRepoManager target;
...
[SetUp]
public void SetUp()
{
myRepoMock = new Mock<IMyRepository>();
target = new MyRepoManager(myRepoMock.Object);
}
[Test]
public async Task MyMoqTest()
{
//Arrange
myRepoMock
.Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
.Returns(Task.FromException<Result>(new DatabaseTimeoutException()));
//myRepoMock
// .Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
// .Throws<DatabaseTimeoutException>(); <- The same result as above
//Act
Result taskResult = await target.RunTask(int someInt); //Calls repository method - DoSomeWork
//Assert
Assert.AreEqual(Result.Error, taskResult.Result);
}
But what happens is that the repository throws the DatabaseTimeoutException without returning the Result.Error, and the test fails with the message (as expected):
MyExceptions.DatabaseTimeoutException : Exception of type 'MyExceptions.DatabaseTimeoutException' was thrown.
I'm very new to Moq, and so my question is - can this be done with Moq, and if so, how would I go about doing so?
Thanks.
The most important part of unit testing is to identify the System Under Test (SUT). That's the thing that you'll actually be verifying works. Once you've identified that, all dependencies of your SUT should be mocked, so that you can tightly control everything external to the thing you're testing.
If you're trying to unit test MyRepoManager.RunTask, then it should not care about any of the internal implementation details of its dependencies. It should only care about the contract that they expose. In this case, you have a dependency on IMyRepository. So it's irrelevant what the concrete implementation MyRepository does. MyRepository might handle DatabaseTimeoutException and DatabaseDeadlockException internally, but that's an implementation detail, not part of the contract defined via IMyRepository. The goal is to mock the behavior of the dependencies, not completely reimplement the dependencies internal behavior within a mocking framework.
So, your mock setup should be:
myRepoMock
.Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
.Returns(Task.FromResult(Result.Error));
I'm trying to register decorator for service these uses property injection.
When I'm adding containerBuilder.RegisterDecorator<ServiceDecorator, IService>() that properties are no longer injected.
I guess Autofac is trying to inject it to the decorator instead of original service.
I've written some tests to showcase this problem. There are services and the decorator:
public interface IService
{
bool NestedServiceIsNotNull();
}
public interface INestedService { }
public class Service : IService
{
public INestedService NestedService { get; set; }
public bool NestedServiceIsNotNull()
{
return NestedService != null;
}
}
public class NestedService : INestedService { }
public class ServiceDecorator : IService
{
private readonly IService _original;
public ServiceDecorator(IService original)
{
_original = original;
}
public bool NestedServiceIsNotNull()
{
return _original.NestedServiceIsNotNull();
}
}
And the test methods:
[TestMethod]
public void PropertyInjectedServiceShouldNotBeNull()
{
var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();
builder.RegisterType<Service>().As<IService>().PropertiesAutowired();
var container = builder.Build();
var service = container.Resolve<IService>();
Assert.IsTrue(service.NestedServiceIsNotNull());
}
[TestMethod]
public void PropertyInjectedServiceShouldNotBeNullEvenIfDecoratorRegistered()
{
var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();
builder.RegisterType<Service>().As<IService>().PropertiesAutowired();
// Here's the difference - decorating the service
// causes the assertion to fail.
builder.RegisterDecorator<ServiceDecorator, IService>();
var container = builder.Build();
var service = container.Resolve<IService>();
Assert.IsTrue(service.NestedServiceIsNotNull());
}
The first test passes but the second fails by assertion.
Is it correct behavior?
I'm working with a legacy project, so I shouldn't to change existing code by moving dependencies to the constructor.
Is there any way to solve this problem?
It appears... you've found a bug! Yow! I've filed an issue on your behalf here.
All is not lost, however - you can still use decorators the way you want, you'll just have to use the older less-pretty Autofac decorator syntax to get it done.
var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();
// Decorating the service with the old syntax works.
builder.RegisterType<Service>().Named<IService>("service").PropertiesAutowired();
builder.RegisterDecorator<IService>((c, inner) => new ServiceDecorator(inner), fromKey: "service");
var container = builder.Build();
var service = container.Resolve<IService>();
Assert.True(service.NestedServiceIsNotNull());
There is more documentation on how to work with this older syntax here.
I'm having a difficult time trying to understand how to appropriately return mocked data from a simulated database call in a unit test.
Here's an example method I want to unit test (GetBuildings):
public class BuildingService : IBuildingService {
public IQueryable<Building> GetBuildings(int propertyId)
{
IQueryable<Building> buildings;
// Execution path for potential exception thrown
// if (...) throw new SpecialException();
// Another execution path...
// if (...) ...
using (var context = DataContext.Instance())
{
var Params = new List<SqlParameter>
{
new SqlParameter("#PropertyId", propertyId)
};
// I need to return mocked data here...
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
So GetBuildings calls a stored procedure.
So I need to mock the DataContext, that of which I can override and set a testable instance. So what happens here is, in the above example DataContext.Instance() does return the mocked object.
[TestFixture]
public class BuildingServiceTests
{
private Mock<IDataContext> _mockDataContext;
[SetUp]
public void Setup() {
_mockDataContext = new Mock<IDataContext>();
}
[TearDown]
public void TearDown() {
...
}
[Test]
public void SomeTestName() {
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
DataContext.SetTestableInstance(_mockDataContext.Object);
var builings = BuildingService.GetBuildings(1, 1);
// Assert...
}
Please ignore some of the parameters, like propertyId. I've stripped those out and simplified this all. I simply can't get the ExecuteQuery method to return any data.
All other simple peta-poco type methods I can mock without issue (i.e. Get, Insert, Delete).
Update
DataContext.Instance returns the active instance of the DataContext class, if exists, and if not exists, returns a new one. So the method of test under question returns the mocked instance.
Do not mock DataContext. Because mocking DataContext will produce tests tightly coupled to the implementation details of DataContext. And you will be forced to change tests for every change in the code even behavior will remain same.
Instead introduce a "DataService" interface and mock it in the tests for BuildingService.
public interface IDataService
{
IEnumerable<Building> GetBuildings(int propertyId)
}
Then, you can tests implementation of IDataService agains real database as part of integration tests or tests it agains database in memory.
If you can test with "InMemory" database (EF Core or Sqlite) - then even better -> write tests for BuildingService against actual implementation of DataContext.
In tests you should mock only external resources (web service, file system or database) or only resources which makes tests slow.
Not mocking other dependencies will save you time and give freedom while you refactoring your codebase.
After update:
Based on the updated question, where BuildingService have some execution path - you can still testing BuildingService and abstract data related logic to the IDataService.
For example below is BuildingService class
public class BuildingService
{
private readonly IDataService _dataService;
public BuildingService(IDataService dataService)
{
_dataService = dataService;
}
public IEnumerable<Building> GetBuildings(int propertyId)
{
if (propertyId < 0)
{
throw new ArgumentException("Negative id not allowed");
}
if (propertyId == 0)
{
return Enumerable.Empty<Building>();
}
return _myDataService.GetBuildingsOfProperty(int propertyId);
}
}
In tests you will create a mock for IDataService and pass it to the constructor of BuildingService
var fakeDataService = new Mock<IDataContext>();
var serviceUnderTest = new BuildingService(fakeDataService);
Then you will have tests for:
"Should throw exception when property Id is negative"
"Should return empty collection when property Id equals zero"
"Should return collection of expected buildings when valid property Id is given"
For last test case you will mock IDataService to return expected building only when correct propertyId is given to _dataService.GetBuildingsOfProperty method
In order for the mock to return data is needs to be set up to behave as expected given a provided input.
currently in the method under test it is being called like this
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
Yet in the test the mock context is being setup like
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
Note what the mock is told to expect as parameters.
The mock will only behave as expected when provided with those parameters. Otherwise it will return null.
Consider the following example of how the test can be exercised based on the code provided in the original question.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
DataContext.SetTestableInstance(_mockDataContext.Object);
var subject = new BuildingService();
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
That said, the current design of the system under test is tightly coupled to a static dependency which is a code smell and makes the current design follow some bad practices.
The static DataContext which is currently being used as a factory should be refactored as such,
public interface IDataContextFactory {
IDataContext CreateInstance();
}
and explicitly injected into dependent classes instead of calling the static factory method
public class BuildingService : IBuildingService {
private readonly IDataContextFactory factory;
public BuildingService(IDataContextFactory factory) {
this.factory = factory
}
public IQueryable<Building> GetBuildings(int propertyId) {
IQueryable<Building> buildings;
using (var context = factory.CreateInstance()) {
var Params = new List<SqlParameter> {
new SqlParameter("#PropertyId", propertyId)
};
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
This will allow for a proper mock to be created in injected into the subject under test without using a static workaround hack.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
var factoryMock = new Mock<IDataContextFactory>();
factoryMock
.Setup(_ => _.CreateInstance())
.Returns(_mockDataContext.Object);
var subject = new BuildingService(factoryMock.Object);
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
I write integration tests for my application, and use my container for this. I want to be able to register all the components as I do in real running, and then override some of the components and switch them to use stubs implementations.
I wouldn't want to seperate the DI and have a container for tests only because I want to test the real thing.
Doing this also seems ugly:
public class MyRegistrations
{
public static RegisterAll(bool isInTest= false)
{
if (isTest)
{
// Register test fakes
}
else
// Register real components
}
}
So I thought of overriding registrations in my test enviorment. How should it be done?
Any other better ways for achieving my goal?
Thanks
Autofac will use the last registered component as the default provider
of that service
From the AutoFac documation.
In your arrange/setup/testInit phase register the mocks, then resolve the SUT:
[SetUp]
public void TestInit()
{
Mock<IFoo> mock = new Mock<IFoo>();
builder.RegisterInstance(mock.object).As<IFoo>();
...
...
_target = builder.Resolve<The component>();
}
Note:
Singletons, static members and SingletonLifestyle(registration) may cause some troubles....
Well, for example you can create a static action method inside your composition root to alter the current configuration and call it during testing. For example:
public class CompositionRoot
{
public static Action<IContainer> OverrideContainer = c => { };
internal static IContainer CreateContainer()
{
ContainerBuilder builder = new ContainerBuilder();
/// etc. etc.
var container = builder.Build();
OverrideContainer(container);
return container;
}
}
After that you can create a mock of you server, for example, like this:
[TestFixture]
public class ConfigurationControllerFixture : BaseServer
{
[Test]
public async Task verify_should_get_data()
{
var response = await GetAsync(Uri);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
protected override string Uri
{
get { return "api/configuration"; }
}
}
public abstract class BaseServer
{
protected TestServer Server;
protected abstract string Uri { get; }
protected virtual void OverrideConfiguration()
{
CompositionRoot.OverrideContainer = c =>
{
// new autofac configuration
cb.Update(c);
};
AppStartup.OverrideConfiguration = c =>
{
// same as explained, but for HttpConfiguration
};
}
}
[SetUp]
public void Setup()
{
OverrideConfiguration();
Server = Microsoft.Owin.Testing.TestServer.Create(app =>
{
var startup = new AppStartup();
startup.Configuration(app);
});
PostSetup(Server);
}
Hope it helps :)
If you want to write integration test from API to database you can use XUnit. XUnit use TestHost and WebApplicationFactory to create a System under test. With XUnit, it's very easy to mock a test service by add test service to service collection.
I made a open source project use XUnit to test my API work with mySQL database. Please visit here for example https://gitlab.com/quorion-group/quorion-backend-crm
I'm working on proving out using Dependency Injection with some numerous DI frameworks. I'm attempting to try to unit test some classes currently using Autofac as the DI container.
Let's say I have this class...
public class SaveUserCommand : DBCommandBase<UserImpl>
{
public delegate SaveUserCommand Factory(UserImpl impl);
private UserImpl impl;
private IAuditableHelper helper;
public SaveUserCommand(UserImpl impl, IAuditableHelper helper)
{
this.impl = impl;
this.helper = helper;
}
public override UserImpl Execute(object dataTrans)
{
return this.impl;
}
}
^Command structured business layer btw.
I have another command that relies on the above command in this way...
public class SaveSpecialUserCommand : DBCommandBase<UserImpl>
{
public delegate SaveSpecialUserCommand Factory(UserImpl user);
private UserImpl user;
SaveUserCommand.Factory saveUserCommand;
public SaveSpecialUserCommand(UserImpl user, SaveUserCommand.Factory saveUserCommand)
{
this.user = user;
this.saveUserCommand = saveUserCommand;
}
public override UserImpl Execute(object dataTrans)
{
this.user.IsSpecial = true;
this.saveUserCommand(this.user).Execute(dataTrans);
return this.user;
}
}
Using Autofac, it resolves all dependencies in the SaveSpecialUserCommand.
What I am unsure of, is how I can unit test or inject a mock into the SaveUserCommand.Factory delegate.
Hints would be good. I still want to figure this out, but a general direction would be awesome.
EDIT
Just adding a simple test case showing I do not want to use Autofac in my unit tests to create my commands.
[Test]
public void SomeSimpleTestTest()
{
var user = new UserImpl();
var command = new SaveSpecialUserCommand(user, /*This is what I need to mock. SaveUserCommand.Factory*/null);
var retVal = command.Execute(this._mockTransaction);
Assert.IsNotNull(retVal);
Assert.IsTrue(retVal.IsSpecial);
}
If you resolve SaveSpecialUserCommand through the container, you can't mock the factory delegate since this is a piece that Autofac autogenerates for you. The question is then, why do you need to fake the actual delegate?
Update: bit of misunderstanding initially there. To "fake" a delegate you can simply use a lambda, like this:
var user = new UserImpl();
var cmd = new SaveUserCommand(...);
var command = new SaveSpecialUserCommand(user, u => cmd);