Mock Autofac.IComponentContext with unit tests c# - c#

I am trying to mock IComponentContext with NSubstitute as below:
[TestClass()]
public class SyncRepositoryFactoryTests
{
private IComponentContext _container;
private SyncRepositoryFactory _factory;
[TestInitialize]
public void Initialize()
{
_container = Substitute.For<IComponentContext>();
_factory = new SyncRepositoryFactory(_container);
}
[TestMethod]
public void Get_SyncRepositoryOfITestEntity_Success()
{
var repository = Substitute.For<IRepository<TestEntity>>();
_container.Resolve<IRepository<TestEntity>>().Returns(repository);
var result = _factory.Get<ITestEntity>();
Assert.IsNotNull(result);
Assert.IsTrue(result is ISyncRepository<ITestEntity>);
}
public interface ITestEntity
{
}
public class TestEntity : ITestEntity
{
}
}
but I get an exception:
ComponentNotRegisteredException: The requested service
'Hvb.eMarketAdvisor.Repository.SharePoint.IRepository`1[[Hvb.eMarketAdvisor.
Repository.SharePoint.Tests.Units.SyncRepositoryFactoryTests+TestEntity,
Hvb.eMarketAdvisor.Repository.SharePoint.Tests.Units,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' has not been registered.
To avoid this exception, either register a component to provide the service,
check for service registration using IsRegistered(), or use the ResolveOptional()
method to resolve an optional dependency.
As I try to create a mock why does IComponentContext try to resolve dependency?

Because Resolve<>() is an extension method and so you're just executing the extension method, not mocking its call. You need to mock the call that the extension method calls.
As the commenters above have said, if you're mocking your DI container, something is wrong with your design.

Old question but if anyone comes here looking for how to it do for whatever your reason is, as of Autofac 4.9.2 the following should work for you. Obviously if you need more logic you can get fancy with the substitutions.
public interface ICalculate
{
bool ProcessData();
}
public class ReallyCoolCalculate : ICalculate
{
public bool ProcessData()
{
return 2 + (2 * 3) == 8;
}
}
public void GetCalculateFromAutoFac()
{
var calculate = new ReallyCoolCalculate();
var componentContext = Substitute.For<IComponentContext>();
var componentRegistration = Substitute.For<IComponentRegistration>();
componentContext.ComponentRegistry.TryGetRegistration(Arg.Any<Service>(), out Arg.Any<IComponentRegistration>()).Returns(true);
componentContext.ResolveComponent(Arg.Any<IComponentRegistration>(), Arg.Any<IEnumerable<Parameter>>()).Returns(calculate);
var calculateFromAutoFac = componentContext.Resolve<ICalculate>();
}

Related

How to cast Moq object to check type for dependency injection

I have created a wrapper class for the Microsoft DependencyInjection to simplify some of the calls in my application. I am trying to write unit tests that use Moq to insert objects into the dependency injection service.
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;
public static class DiService
{
private static IServiceProvider diProvider;
private static Dictionary<Type, object> mockCollection = new Dictionary<Type, object>();
public static IServiceCollection ServiceCollection { get; } = new ServiceCollection();
public static bool UseTestMode { get; set; } = false;
public static T GetRequiredService<T>()
where T : class
{
if( UseTestMode )
{
if( mockCollection.ContainsKey(typeof(T)) )
{
return mockCollection[typeof(T)] as T;
}
}
if( diProvider == null )
{
diProvider = ServiceCollection.BuildServiceProvider();
}
return diProvider.GetRequiredService<T>();
}
public static void RegisterMock(Type interfaceType, object mockObjectInstance)
{
if( !mockObjectInstance.GetType().IsInstanceOfType(interfaceType) )
{
throw new InvalidCastException($"mockObjectInstance must be of type {interfaceType}");
}
if( mockCollection.ContainsKey(interfaceType) )
{
mockCollection[interfaceType] = mockObjectInstance;
}
else
{
mockCollection.Add(interfaceType, mockObjectInstance);
}
}
}
Testing related code
public interface ITestInterface
{
}
public class TestClass : ITestInterface
{
}
[Fact]
public void GetRequiredService_MoqObject_NormalOperation()
{
Mock<ITestInterface> mock = new Mock<ITestInterface>();
DiService.UseTestMode = true;
DiService.RegisterMock(typeof(ITestInterface), mock.Object);
ITestInterface testResult = DiService.GetRequiredService<ITestInterface>();
Assert.NotNull(testResult);
}
This works great for mocks that I great myself, but not when I try to use Moq. The InvalidCastException is thrown for Moq objects.
In the RegisterMock method, I haven't been able to figure out how to cast the Moq object to check if it implements the proper interface. The Moq object actually doesn't inherit from the interface it's mocking (the interface is ITestInterfaceProxy). I also can't figure out how to cast an object to a type specified by a variable.
Is there any way to actually perform the error check in RegisterMock?
Thanks ahead of time for your responses.
Addendum:
Based on Peter Csala's comment, I am adding this example of how I'm using the DiService above. I hope I haven't simplified it to the point of uselessness.
[Fact]
public void TestLoad()
{
DiService.UseTestMode = true;
Mock<IDataAccess> mockDataAccess = new Mock<IDataAccess>();
DiService.RegisterMock(typeof(IDataAccess), mockDataAccess.Object);
Data testData = GenFu.A.New<Data>();
mockDataAccess.Setup(mock => mock.LoadData(It.IsAny<string>()).Returns(testData);
// Assuming that inside MyViewModel.LoadData there is some process that generates an IDataAccess and calls IDataAccess.LoadData
MyViewModel viewModel = new MyViewModel();
Data loadedData = viewModel.LoadData("some id");
Assert.Equal(testData, loadedData);
}
Just to clarify certain things:
I am trying to write unit tests that use Moq to insert objects into the dependency injection service
In case of unit testing the DI is not in use. Rather you explicitly pass the mocked object to your system under test. For example:
Your System under test class
private readonly IDependency dependency;
public SampleUsage(IDependency dep)
=> dependency = dep;
Your test code
//Arrange
Mock<IDependency> mockedDep = new Mock<IDependency>();
mockedDep.Setup(...).Returns(...);
var sut = SampleUsage(mockedDep.Object);
//Act
var actualResult = sut.XYZMethod();
In case of integration or end-to-end testing you rely on the DI system, but not by replacing some components with a mocked one. Rather you are using different configuration options.
For example if you have a component that communicates with a 1st or 3rd party REST service then you should change the base address configuration of that service. That new address should point to a locally running http mock server. You can create one with a library like WireMock.NET.

Ninject Get<T> with constructor argument

Here is my Module:
public class LoggerModule : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<NLogLogger>()
.WithConstructorArgument(
typeof(Type),
x => x.Request.ParentContext.Plan.Type);
}
}
So as you can see the NLogLogger is expecting the Type to be passed into the constructor.
This is my Unit Test:
[Test]
public void ResolveLoggerDependency()
{
var module = new LoggerModule();
var kernal = new StandardKernel(module);
var service = kernal.Get<ILogger>(new ConstructorArgument("type", typeof(int)));
Assert.That(service, Is.Not.Null);
}
It is throwing a null reference error on the kernal.Get<ILogger> so I can only assume I am not passing the constructor value correctly. How can I pass in a Type when using Get<T>?
So, this question as it seems relates to your other question.
The requirement in that question was to inject into NLogLogger the type of the object into which the it will be injected.
The registration in this case is assuming that this interface ILogger will not be resolved outside the context of a parent class into which it will be injected. And you are getting the exception because there is no parent class context when you directly attempt to resolve the ILogger interface.
I am assuming that in your unit test, your would like to test that this registration actually work. I would suggest the following:
First, create a class the you will use in your tests:
public class TestClass
{
private readonly ILogger m_Logger;
public TestClass(ILogger logger)
{
m_Logger = logger;
}
public ILogger Logger
{
get { return m_Logger; }
}
}
And then use such class in your unit tests like this:
[Test]
public void ResolveLoggerDependency()
{
var module = new LoggerModule();
var kernal = new StandardKernel(module);
var test_object = kernal.Get<TestClass>();
Assert.That(test_object.Logger, Is.Not.Null);
}
You can further verify that the NLogLogger actually used the TestClass class's name to construct the NLog logger. This might require the use of Reflection though, I am not sure.
In your Load method you can just set it up using Bind<ILogger>().To<NLogLogger>();

How to deal with an IDisposable repository with Unity?

I have a job in which I have an IDisposable DbContext. I would like to unit test this job without hitting in a database. What options do i have to do this?
Im using the default Fakes assembly' of microsoft.
My job:
public void Work()
{
do
{
//code here
using (var repository = new Repository<User>())
{
repository.Save(user);
}
} while (true);
}
I'm trying to test and in this part of the test it fails because it actually creates a new instance of the Repository class.
My test Method:
using (ShimsContext.Create())
{
Data.Repository.Fakes.ShimRepository<Domain.Fakes.ShimUser>.Constructor = (a) => { };
Data.Repository.Fakes.ShimRepository<Domain.Fakes.ShimUser>.AllInstances.SaveT0 = (a, b) =>
{
};
var service = GetService();
service.Work(); //Throws exception
}
How can I fake this Save method?
You've violated DIP here, making unit testing your service far more difficult than it should be. You should also avoid generic repositories and favour role interfaces.
Instead, inject an abstraction into your service of your repository, e.g. IUsersRepository which defines your Save method. Then in your unit test of the service you can simply use a stub implementation of IUsersRepository.
Fakes tend to reveal that your code is not properly following the D in SOLID since you are creating dependencies inside your class instead of passing them in.
A much better pattern would to create an ISaveRepository interface that in turn implements IDisposable with an exposed Save() method. You should then inject an instance of your repository into your class. This will allow you to satisfy the using statement testing, as well as implement a mock that defines a .Save() method that does not hit the database.
public class Test
{
private readonly ISaveRepository _userRepository;
public Test(ISaveRepository userRepository)
{
_userRepository = userRepository;
}
public void Work()
{
using (_userRepository)
{
var cont = true;
do
{
_userRepository.Save(new User());
cont = false;
} while (cont);
}
}
}
public interface ISaveRepository : IDisposable
{
void Save<T>(T model);
}
public class Repository<T> : ISaveRepository
{
public void Dispose() { }
public void Save<TT>(TT model) {}
}
public class User {}

Autofac delegate factories, and passing around container

I have a question about delegate factories: autofac docs
I understand how they set up the factories but I do not get the resolving part:
var shareholdingFactory = container.Resolve<Shareholding.Factory>();
var shareholding = shareholdingFactory.Invoke("ABC", 1234);
It looks like you have to pass around the container in order to resolve. Maybe I have to Invoke something with parameters I only know at runtime. How do I do that without passing the container to for example a service method?
UPDATE
So you are supposed to pass the factories instead?
Autofac can automatically resolve factories, i.e. without the container:
public class ShareHolding
{
public ShareHolding(int accountId)
{
// do whatever you want
}
}
public class MyApp
{
private readonly ShareHolding _shareHolding;
public MyApp(Func<int, ShareHolding> shareHoldingFactory)
{
_shareHolding = shareHoldingFactory(99);
}
public void Run()
{
// do whatever you want with the _shareHolding object
}
}
Autofac registration
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ShareHolding>(); // not a singleton
containerBuilder.RegisterType<MyApp>().SingeInstance();
var myApp = containerBuilder.Resolve<MyApp>();
myApp.Run();
Now, if your ShareHolding type had ctor like:
public class ShareHolding
{
public delegate ShareHolding Factory(int accountId, int userId);
public ShareHolding(int accountId, int userId)
{
// do whatever you want
}
}
Then you would need a delegate factory because Autofac resolves constructors using type information and delegate factories using parameters names. Your usage would then become:
public class MyApp
{
public MyApp(ShareHolding.Factory shareHoldingFactory)
{
....
}
}

How to moq a static class with a static method (UnitOfWork case)?

I have these classes:
public static class UnitOfWorkSS
{
public static IUnitOfWork Begin()
{
return IoC.Resolve<IUnitOfWork>();
}
}
public class PostService
{
using (IUnitOfWork unitOfWork = UnitOfWorkSS.Begin())
{
//don't forget to sanitize html content
htmlContent = _htmlSanitizer.Sanitize(htmlContent);
IPost post = _factory.CreatePost(byUser, title, htmlContent);
_postRepository.Add(post);
unitOfWork.Commit();
}
}
How can I mock the classes UnitOfWorkSS and unitOfWork?
It looks like the only thing you are doing with the call to Begin() is returning your configured class for that particular interface: IUnitOfWork
You really just need to make sure that your call to Begin() returns a mock implementation of IUnitOfWork
One of two ways you can do this:
Option One - Refactor UnitOfWorkSS so that you can set the instance of IUnitOfWork to be returned
public static class UnitOfWorkSS
{
private static IUnitOfWork _unitOfWork;
public static IUnitOfWork UnitOfWork
{
set { _unitOfWork = value; }
private get{ _unitOfWork ?? (_unitOfWork = IoC.Resolve<IUnitOfWork>()); }
}
public static IUnitOfWork Begin()
{
return UnitOfWork;
}
}
[TestMethod]
public void DoStuff()
{
var mockUnitOfWork = new Mock<IUnitOfWork>();
UnitOfWorkSS.UnitOfWork = mockUnitOfWork.Object;
//Do some setup and verify
}
Option Two - Simply register a mock instance of IUnitOfWork with your IoC Container
private Mock<IUnitOfWork> _mockUnitOfWork;
[TestInitialize]
public void Init()
{
_mockUnitOfWork = new Mock<IUnitOfWork>();
//Making a lot of assumptions about your IoC here...
IoC.Register<IUnitOfWork>(_mockUnitOfWork.Object);
}
[TestMethod]
public void DoStuff()
{
_mockUnitOfWork.Setup( ... );
//Do some verification
}
Mock the IUnitOfWork and register it into your container so that it can be resolved.
As far as I know, you cannot mock static classes or methods.
I realize this is a very old question, but in case someone ends up here...
The best solution is a design change like the other answers say. However, if that's not possible, you can either use Microsoft Fakes (which replaced Moles) or, if you'd rather not depend on Visual Studio, there is a library called Smocks that can help.
https://github.com/vanderkleij/Smocks

Categories

Resources