Search code examples
c#moqxunit

How to create private dependency method setup using Moq


I have the following Controller interface:

public interface IInformationController
{
  string GetStoredInformation();
  string GetInformation();
}

The controller class is the following:

public class InformationController : ControllerBase, IInformationController
{
  private InformationProvider1 InformationProvider1;
  private InformationProvider2 InformationProvider2;
  private IBasicRepository repository;

  public InformationController(IBasicRepository basicRepository)  
    => repository = basicRepository;

  public string GetStoredInformation()
    => repository.GetStoredInformation();

  public string GetInformation()
    => $"Information is {informationProvider1.GetInformationHeader()}, Information detail is {informationProvider2.GetInformationDetail()}";
  
}

I intend to create a unit test for the InformationController with xUnit and Moq.

This is my test class:

public class InformationControllerTest
{
  public InformationControllerTest()
  {
    repositoryMock = new Mock<IBasicRepository>();
    repositoryMock.Setup(repository => repository.GetStoredInformation()).Returns("Stored information");
    SUT = new InformationController(repositoryMock.Object);
  }

  [Fact]
  public void GetStoredInformation_Returns_Stored_Information()
  {
    string result = SUT.GetStoredInformation();
    Assert.Equal("Stored information", result);
  }

  [Fact]
  public void GetInformation_Returns_Valid_Information()
  {
    string result = SUT.GetInformation(); //TODO: how to avoid the usage of actual provider implementations?
    Assert.Equal("Information is Header1, Information detail is Detail1", result);
  }
}

As you can see, there are private providers. Unfortunately they are external dependencies and can't easily be introduced via dependency injection.

How should I mock their actual calls? Should I mock the controller method (which imho should invalidate the process of testing the actual controller)? Should I try to get them via dependency injection?


Solution

  • The unit test is exposing the short comings of your current design, which is tightly coupling to external dependencies or implementation concerns.

    Dependencies should be explicitly injected into their dependents

    Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.

    Reference Explicit Dependencies Principle

    public class InformationController : ControllerBase, IInformationController {
        private IInformationProvider1 informationProvider1;
        private IInformationProvider2 informationProvider2;
        private IBasicRepository repository;
    
        public InformationController(IBasicRepository basicRepository,
            IInformationProvider1 informationProvider1, 
            IInformationProvider2 informationProvider2) {
            repository = basicRepository;
            this.informationProvider1 = informationProvider1;
            this.informationProvider2 = informationProvider2
        }
    
        public string GetStoredInformation()
            => repository.GetStoredInformation();
    
        public string GetInformation()
            => $"Information is {informationProvider1.GetInformationHeader()}, Information detail is {informationProvider2.GetInformationDetail()}";
      
        //...
    }
    

    Create abstractions and implementations for those external dependencies, then register them with the DI container so that they can be resolved and properly provided to the controller at run-time. This will now allow them to also be tested in isolation without undesired side effects from their actual implementations.