Search code examples
c#unit-testingnunitninjectmoq

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?


Solution

  • 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).