Mocking StandardKernal Interface with Ninject - c#

I'm working on adding unit tests to some legacy ASP code with Moq and the Ninject.MockingKernal.
public class BaseController : Controller
{
private IAuthenticationManager authenticationManager;
public ILog log;
public BaseController()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
log = kernel.Get<ILog>();
}
}
The Log Interface:
public interface ILog
{
AuditTrail Create(AuditAction action, string description = null);
AuditTrail Create(AuditAction action, long reservationId, string description = null);
AuditTrail Create(IUser user, AuditAction action);
AuditTrail Create(IUser user, AuditAction action, string description = null);
AuditTrail Create(IUser user, AuditAction action, long reservationId, string description = null);
}
I'm trying to mock the log instance that is set up from the kernel. This log is inherited by other controllers and is not injected. I want to be able to return a mock object when it's requested, much like I would do in other cases (such as returning a mock DatabaseContext from a factory).
I've looked at this How to do Setup of mocks with Ninject's MockingKernel (moq) and the GitHub example: https://github.com/ninject/Ninject.MockingKernel/wiki/Examples, as well as many others.
From what I've gathered, I need to do something along these lines:
mockingKernal = new MoqMockingKernel();
mockingKernal.Bind<ILog>().To<Logging.Log>();
var foo = mockingKernal.GetMock<ILog>();
foo.Setup(x => x.Create(It.IsAny<AuditAction>(), It.IsAny<long>(), It.IsAny<string>()));
However, if I run this, I get an error System.ArgumentException: Object instance was not created by Moq. From what I can find online, this is caused by the class having a parameter in the constructor, but in this case, the Log class does not.
Am I approaching this in the correct way? And if I am, what am I doing wrong? Any help would be greatly appreciated

The above approach/design is going to cause all manner of head aches to maintain/test as the controller is tightly coupled to the kernel (IoC container) which basically does not allow one to be able to easily mock/replace it for testing.
Also note that the examples linked in question all have in common the ability to explicitly inject the dependencies into their subjects under test.
The above is basically using the kernel as a service locator.
Trying to put lipstick on that code may change its appearance but does nothing about the smell.
Ideally the design should be following the explicit dependency principle.
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
public class BaseController : Controller {
private IAuthenticationManager authenticationManager;
public ILog log;
public BaseController(ILog log, IAuthenticationManager authenticationManager) {
this.log = log;
this.authenticationManager = authenticationManager;
}
}
which would allow the dependencies to be mocked/faked/stubbed and injected into their dependents.
//Arrange
var logger = new Mock<ILog>();
logger
.Setup(_ => _.Create(It.IsAny<AuditAction>(), It.IsAny<long>(), It.IsAny<string>()))
.Return(new AuditTrail);
var controller = new BaseController(logger.Object, null);
//Act
//...
One should not be calling the container directly within classes but rather configure it at the composition root.
I suggest reviewing the current design and refactoring accordingly.

Related

unit test for a method that takes an instance through Resolve<T> of Autofac

I'm facing a problem trying to implement a unit test for a method on a service.
The architecture of the project is a little bit cumbersome, to say the less...
The problem is that within the method to test it calls another method to take an instance of another service, here is the little monster:
public void SendOrderEmail(string orderCode)
{
Order order= GetOrderService().SerachByCode(orderCode);
.... Send email with the order ....
}
private IOrderService GetOrderService()
{
return OrderService = AutofacDependencyResolver.Current.ApplicationContainer.Resolve<IOrderService>();
}
Please, don't ask why a service calls another service or why is that service not injected at the constructor, as i said the architecture of this project is weird in some points.
I just need to know what is the way to implement a unit test for a method like that.
Thank you!
I would refactor a little the code, let the class that implement this method have IOrderService injected through the constructor, save the instance and then use it,
this way you can inject your fake IOrderService during the test (or use Automock) :)
If you really really can't change the constructor, you can use a property to set IOrderService
---------------- edit
Since i got some downvote on this answer I've tried to get to understand better what is going on.
I'm not sure about this, but seems like you can't edit this class you wrote about, you just want to test it.
Well if that is the case i think i can still give you some advices.
Advice number one: make a test project, link the class file, make a new file with a class like the following one.
class AutofacDependencyResolver {
public static Current { get; private set; }
public ILifetimeScope ApplicationContainer { get; private set; }
public AutofacDependencyResolver(ILifetimeScope scope) {
Current = this;
ApplicationContainer = scope;
}
}
Since the class you need to test is linked it's gonne to compile it and you just can now achieve what you need.
The other (and i think better) advice is do not test stuff you did not wrote / can't modify. What i'm suggesting is writing an adapter, so a class that use the one you can't modify as a black box.
In this case i think you need to test the email, so just check the email output the address stuff like that and ignore the rest.
the people who wrote those classes should have followed solid principles...
As others have said, and you're probably aware yourself anyway, you really want to refactor classes like this and use constructor injection if at all possible. Service location is generally considered an anti-pattern (https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/) and it specifically makes unit testing like this harder and less transparent.
However, if you absolutely can't refactor, you can still make methods like this somewhat testable by just providing different registrations for the services you're accessing via service location.
In your case, if you have:
public class EmailSender
{
public void SendOrderEmail(string orderCode)
{
Order order = GetOrderService().SearchByCode(orderCode);
//....Send email with the order ....
}
private IOrderService GetOrderService()
{
return AutofacDependencyResolver.Current.ApplicationContainer.Resolve<IOrderService>();
}
}
...and you're looking to specifically run unit tests over SendOrderEmail to validate the logic surrounding your IOrderService implementation (which could be easily covered by a separate test), the other classes implied there might look like:
public class AutofacDependencyResolver // this is problematic but we can't change it
{
public AutofacDependencyResolver(IContainer applicationContainer)
{
ApplicationContainer = applicationContainer;
}
public IContainer ApplicationContainer { get; }
public static AutofacDependencyResolver Current { get; private set; }
public static void SetContainer(IContainer container)
{
Current = new AutofacDependencyResolver(container);
}
}
public static class ContainerProvider // this sets up production config across your app
{
public static IContainer GetProductionContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<RealOrderService>()
.As<IOrderService>();
// register all other real dependencies here
return builder.Build();
}
}
With that setup, you only need to provide mocks which are required for the specific method you're testing, assuming you can set your container within AutofacDependencyResolver easily in order to have production and test configuration running in parallel. That might look like the following, using xUnit, Moq and Autofac in a test project:
public class EmailSenderTests
{
private readonly Mock<IOrderService> _orderService;
public EmailSenderTests()
{
// to set up the test fixture we'll create a mock OrderService and store a reference to the mock itself for validation later on
_orderService = new Mock<IOrderService>();
var mockOrder = new Order();
_orderService.Setup(os => os.SearchByCode(It.IsAny<string>()))
.Returns(mockOrder);
}
private IContainer GetTestContainer()
{
// here we're adding just one registration we need, setting the mocked OrderService instance to be used for IOrderService
var builder = new ContainerBuilder();
builder.Register(c => _orderService.Object)
.As<IOrderService>();
return builder.Build();
}
[Fact]
public void SendEmail()
{
AutofacDependencyResolver.SetContainer(GetTestContainer()); // set the test container on the global singleton
var sender = new EmailSender();
sender.SendOrderEmail("abc"); // internally the email sender will retrieve the mock IOrderService via service location
// make any assertions here, e.g.
_orderService.Verify(os=>os.SearchByCode("abc"), Times.Exactly(1));
}
}

How to create nlog loggers for various controllers and asp net mvc filters?

I need to programatically create loggers for each controller (let's say: Documents, Customers and Warehouses, to log some operations inside them) and for a filter above controllers (to log parameters sent to each action). Each controller logic should be logged to another file ex. Documents.csv, Customers.csv and Warehouses.csv.
Currently I have a wrapper for nlog logger. The wrappers are injected to controllers instances via constructor and then nlog logger inside in initialized via LogManager. Initialization creates new target and loglevel and assigns it to LogManager.Configuration.
The problem is that after a few requests each loggers logs to each file, so ex. logic from Customers is logged to Customers.csv and vice versa, same thing with logger from Filters.
How should I then configure separate blog loggers with different target for each controller and separate for filter?
I prefer programmatic configuration than via xms etc.
Adapter as requested:
public class Logger : ILogger
{
private NLog.Logger _logger;
string _deployVersion;
public Logger(string deploymentVersion)
{
_deployVersion = deploymentVersion;
}
public void Init(string loggerName)
{
_logger = NLog.LogManager.GetLogger(loggerName);
}
public void Init(string loggerName, string header, string layout, Level level)
{
LoggingConfiguration config;
if (NLog.LogManager.Configuration == null)
{
config = new LoggingConfiguration();
}
else
{
config = LogManager.Configuration;
}
if (config.FindTargetByName(loggerName) == null)
{
var target = CreateTarget(loggerName, header, layout, level); //configures target: path, archives and layout
config.AddTarget(loggerName, target);
var logLevel = GetLogLevel(level); //translates Level enum to NLog level
var rule1 = new LoggingRule("*", logLevel, target);
config.LoggingRules.Add(rule1);
LogManager.Configuration = config;
}
_logger = LogManager.GetLogger(loggerName);
}
...
//Info, Debug etc. methods
Great, you've used an interface here already which makes a pattern for this easier to produce.
Your main problem here is responsibility, as your controller code will (I assume) call Init(string loggerName, string header, string layout, Level level). This is probably not best practice as you may have to repeat this code a lot and the controller probably shouldn't care about where the log goes or what it's formatted like...just the fact that a log is used.
Instead of injecting these directly, use a Factory to obtain the correct logger type. For example, CustomerLogger : ILogger:
public class LogFactory
{
public ILogger Get<T>() where T : ILogger
{
ILogger instance = null;
if (typeof(T) == typeof(CustomerLogger))
{
instance = (T)Activator.CreateInstance(typeof(T), "CustomerLogger", "Header", "Layout", Level.Verbose);
}
else if (...)
{
...etc
}
return instance;
}
}
This means you can leave the management and creation of ILogger concretes up to the Factory.
Notice I'm passing in string loggerName, string header, string layout, Level level so you can call Init in the CustomerLogger constructor. You then have different implementations of ILogger to suit your needs.
You can then either make the LogFactory use an interface and inject that into your controller, or simply new up the factory in the controller, either way you call LogFactory.Get<T>(). Option A would be better for unit testing purposes.
Hope this helps!

FakeItEasy to test domain services + UnitOfWork

I started doing some experimentation with unit testing so that we can include them in our domain layer. However i dont know if I'm following the right path, thus i'm going to explain what i'm currently doing to see if i'm on the right track. Basically the architecture is like the following there is Domain Layer containing domain models and domain services (ex. User class and UserService class). Then Domain layer communicates with the DAL which implements the Generic Repository pattern together with the Unit of Work. Each domain service class in it's constructor accepts an IUnitOfWork interface, like the following:
public class UserService: IUserService
{
private readonly IUnitOfWork _unitOfWork;
public UserService(IUnitOfWork unitOfwork)
{
this._unitOfWork = unitOfwork;
}
}
In order to creat the unit tests, i decided to go with FakeItEasy framework. So in a UserServiceTest class i did the following:-
private IUserService _userService;
private const int userID = 2013;
[TestInitialize]
public void Initialize()
{
_userService = A.Fake<IUserService>();
A.CallTo(() => _userService.GetUserById(userID)).Returns(new User
{
UserID = userID,
RegistrationDate = DateTime.Now,
});
}
[TestMethod]
public void GetUserByID()
{
var user = _userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
}
When I run the tests, they pass. Is it the correct way of implementing unit tests? Before I was trying a different approach however FakeItEasy was failing with a ProxyGenerator exception. What i was doing is this:-
[TestInitialize]
public void Initialize()
{
_unitOfWork = A.Fake<IUnitOfWork>();
A.CallTo(() => _unitOfWork.UserRepository.FindById(userID)).Returns(new UserDto
{
UserID = userID,
RegistrationDate = DateTime.Now,
});
AutoMapper.Mapper.CreateMap<UserDto, User();
}
[TestMethod]
public void GetUserByID()
{
var userService = new UserService(_unitOfWork);
var user = userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
}
And this was throwing the below exception:-
Result Message:
Initialization method Initialize threw exception. System.ArgumentNullException: System.ArgumentNullException: Value cannot be null.
Parameter name: callTarget.
Result StackTrace:
at FakeItEasy.Creation.ProxyGeneratorSelector.MethodCanBeInterceptedOnInstance(MethodInfo method, Object callTarget, String& failReason)
at FakeItEasy.Configuration.DefaultInterceptionAsserter.AssertThatMethodCanBeInterceptedOnInstance(MethodInfo method, Object callTarget)
at FakeItEasy.Configuration.FakeConfigurationManager.AssertThatMemberCanBeIntercepted(LambdaExpression callSpecification)
at FakeItEasy.Configuration.FakeConfigurationManager.CallTo[T](Expression`1 callSpecification)
at FakeItEasy.A.CallTo[T](Expression`1 callSpecification)
Any feedback would be greatly appreciated. Thanks!
I think your original (second, in the question) test was failing because _unitOfWork.UserRepository is coming back as null in Initialize. Normally FakeItEasy will create an fake object when chained properties are used, but I'm guessing (I have to guess because I don't know anything about the type of UserRepository) that UserRepository's type is not fakeable. In that case, you'd get a null back from _unitOfWork.UserRepository.
Let me jump back to your second test (which was first in your question), then we'll return to what I think you might want to do here.
Looking at your test,
var user = _userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
I see a flaw. You're invoking a method on _userService directly, but _userService is a fake object, so the test doesn't actually involve any of the production code. It's really only exercising FakeItEasy.
I think what we want is sort of a blended approach - something that will exercise the code in a real UserService, without worrying about UserRepository. Maybe something similar to (and I'm not using a compiler here, and don't know what methods are on IUnitOfWork so take this with a grain of salt)
[TestInitialize]
public void Initialize()
{
_unitOfWork = A.Fake<IUnitOfWork>();
A.CallTo(() => _unitOfWork.GetUserById(userID))
.Returns(new User
{
UserID = userID,
RegistrationDate = DateTime.Now,
});
}
[TestMethod]
public void GetUserByID()
{
var userService = new UserService(_unitOfWork);
var user = userService.GetUserById(userID);
Assert.IsInstanceOfType(user, typeof(Domain.User));
Assert.AreEqual(userID, user.userID);
}
Or, if there's nothing useful on IUnitOfWork except for UserRepository, then I think the next step would be to investigate why the type of UserRepository wasn't fakeable (if my guess was right) - is it sealed? Does it lack appropriate and accessible constructors?

How do i mock a Interface with Moq or NInject Mocking Kernel

I just waded through questions and blogs on the subject of mocking and Dependency Injection. Come to a conclusion i just need to mock the interface that is consumed by client. I am looking forward to testing a simple use case here with no idea.
The Contract
public Interface IApplicationService
{
bool DeleteApplication(int id);
ApplicationDto AddApplication(ApplicationDto application);
IEnumerable<ApplicationDto> GetApplications();
}
Implementation ( I am going to mock )
public Class ApplicationService:IApplicationService
{
private EntityFrameworkRepo repo;
public ApplicationService()
{
repo = new EntityFrameworkRepo();
}
public ApplicationDto Add(ApplicationDto dto)
{
//add to dbcontext and commit
}
}
Mocking Code
[Test(Description = "Test If can successfully add application")]
public void CanAddApplication()
{
//create a mock application service
var applicationService = new Mock<IApplicationService>();
//create a mock Application Service to be used by business logic
var applicationDto = new Mock<ApplicationDto>();
//How do i set this up
applicationService.Setup(x => x.GetApplications()).Returns(IEnumerable<applicationDto.Object>);
}
And i for one am sure i need to test the business logic rather than mocking it. So what is it exactly i have to do to test my ApplicationService but then keep the entity framework out.
btw to speak of ApplicationService, it uses constructor injection with NInject. So mocking this with NInject.MockingKernel will setup dependency chain?
There is little or no benefit using dependency injection (IOC) container in unit testing. Dependency injection helps you in creating loose coupled components, and loose coupled components are easier to test, thats it.
So if you want to test some service, just create mockups of it dependencies and pass them to that service as usual (no need to involve IOC container here, I hardly can imagine, that you will need some features of IOC containers - like contextual binding, interception etc. - inside unit test).
If you want your ApplicationService to be easy to test, it should look more like:
public class ApplicationService: IApplicationService
{
private readonly IEntityFrameworkRepo repo;
// dependency passed by constructor
public ApplicationService(IEntityFrameworkRepo repo)
{
this.repo = repo;
}
// save to db when DTO is eligible
public ApplicationDto Add(ApplicationDto dto)
{
// some business rule
if(dto.Id > 0 && dto.Name.Contains(string.Empty)){
//add to dbcontext and commit
}else{
throw new NotEligibleException();
}
}
}
Here the dependency is passed by constructor. In your application code you will use it together with an IOC container to make constructor injection (IOC container will be responsible for creating instances of IEntityFrameworkRepo).
But in unit test, you can just pass instance of some implementation of IEntityFrameworkRepo created on your own.
ApplicationDto
As long as ApplicationDto is some object that can by created by hand, I can directly use it in unit-test (creating instances by hand). Otherwise I will have to wrap it by interface like IApplicationDto, in order to be able to mock it up with Moq.
public class ApplicationDto{
public int Id {get; set;}
public string Name {get; set;}
}
Here is how could unit-test look like:
In unit test I will use mocked implementaion of IApplicationRepo, because I do not want to configure e.g. database connections, web services etc. and my primary intention is to test the ApplicationService not the underlying repository. Another advantage is that the test will be runnable without specific configuration for various machines. To mockup some db repository I can use e.g. List.
[Test(Description = "Test If can successfully add application")]
public void CanAddApplicationIfEligible()
{
var repo = GetRepo();
var appService = new ApplicationService(repo);
var testAppDto = new ApplicationDto() { Id = 155, Name = "My Name" };
var currentItems = repo.ApplicationDtos.Count();
appService.Add(testAppDto);
Assert.AreEqual(currentItems + 1, repo.ApplicationDtos.Count());
var justAdded = repo.ApplicationsDto.Where(x=> x.Id = 155).FirstOrDefault();
Assert.IsNotNull(justAdded);
///....
}
private static IEntityFrameworkRepo GetRepo{
// create a mock repository
var listRepo = new List<ApplicationDto>{
new ApplicationDto {Id=1, Name="MyName"}
};
var repo = new Mock<IEntityFrameworkRepo>();
// setup the methods you know you will need for testing
// returns initialzed list instead of DB queryable like in real impl.
repo.Setup(x => x.ApplicationDtos)
.Returns<IQueryable<ApplicationDto>>(x=> listRepo);
// adds an instance of ApplicationDto to list
repo.Setup(x => x.Add(It.IsAny<ApplicationDto>())
.Callback<ApplicationDto>(a=> listRepo.Add(a));
return repo.Object;
}
Note:
There have been realeased an ninject.mockingkernel extension. The approach described in example on wiki can make your unit-test code bit tidier, but the approach described there is definetly not depencdency injection (it is service locator).

How to solve base Controller dependency injection for testing purposes?

I have implemented my mvc base controller called DefaultController using dependency injection pattern in order to be able to construct test cases. Example below:
public class DefaultController : Controller
{
protected readonly ISessionHelper _sessionHelper;
string _thisUserOpenID;
protected IUsersRepository _UserRepository;
...
public DefaultController()
{ } //not for testing
public DefaultController(ISessionHelper session, IUserRepository repo)
{
_sessionHelper=session;
_UserRepository = repo;
}
}
Then I have my controllers using this controller, homecontroller, usercontroller, etc.
Now, building some test cases I found myself in a situation where I don't know how to actually use the injection dependency pattern.
[TestMethod]
public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name()
{
// Below I want to insert FakeRepositories using
//ISessionHelper and so on. but the constructor
//for homecontroller don't have it.
HomeController controller = new HomeController();
Any ideas?
Your HomeController needs to have a matching "injectable" constructor, which would then call the base constructor.
public HomeController(ISessionHelper session, IUserRepository repo)
: base(session, repo)
{
}
Now, in your test, you would create your HomeController using that constructor, and pass in a mocked up session and user repository. Speaking of mocking, you might also be interested in Scott Hanselman's MvcMockHelpers classes, with code for many popular mocking frameworks.
I don't see why you have two constructors. You should only have one, get rid of the constructor with no parameters. Using a DI framework like Castle Windsor, or my preferred one, Autofac will handle all of this for you. Then as far as testing is concerned use something like Moq. Ie
public DefaultController(ISessionHelper session, IUserRepository repo)
{
_sessionHelper = session;
_UserRepository = repo;
}
Register DefaultController, ISessionHelper and IUserRepository with your DI framework. Something along the lines of:
Register(new DefaultController()); (it is something like that in Autofac)
Register<SessionHelper>().As<ISessionHelper>();
Register<UserRepository>().As<IUserRepository>();
That way, you can pull DefaultController from the container and the DI framework will inject the two parameters for you. I wrap up a static method to access my DI container, it looks like:
var controller = IoC.Resolve<DefaultController>();
Basically head over to Autofac and have a look. There's also a web module for registering your Controllers for you.
Then for testing just use Moq, or find some form of "AutoMocker" (google it). I would do:
var session = new Mock<ISessionHelper>();
var repo = new Mock<IUserRepository>();
repo.Setup(s => s.FindById(123)).Returns(new User());
var conroller = new DefaultController(session.Object, repo.Object);
controller.Execute();
Also ewww repositories. With .Net and generics etc... just create yourself an nice ISession.
var session = IoC.Resolve<ISession>();
var user1 = session.Get<User>(123);
var user2 = session.Get<User>(u => u.Username == "admin");
session.Update(user3);
Means you only need to pass in one thing and you can use it for whatever. Rather than having to pass in sometimes many repositories. Also sets you up nicely for the Unit Of Work pattern.

Categories

Resources