1

I'm trying to figure out the best way to build my unit tests for an MVC app. I created a simple model and interface, which is used by the controller constructors so that the testing framework (Nsubstitute) can pass a mocked version of the repository. This test passes, as expected.

My problem is now I want to take this a step further and test the file I/O operations in the "real" instantiation of IHomeRepository. This implementation should read a value from a file in the App_Data directory.

I've tried building a test without passing a mocked version of IHomeRepsotory in, however HttpContext.Current is null when I run my test.

Do I need to mock HttpContext? Am I even going about this in the right way?

//The model
public class VersionModel
{
    public String BuildNumber { get; set; }
}



//Interface defining the repository
public interface IHomeRepository
{
    VersionModel Version { get; }
}


//define the controller so the unit testing framework can pass in a mocked reposiotry.  The default constructor creates a real repository
public class HomeController : Controller
{

    public IHomeRepository HomeRepository;

    public HomeController()
    {
        HomeRepository = new HomeRepoRepository();
    }

    public HomeController(IHomeRepository homeRepository)
    {
        HomeRepository = homeRepository;
    }
.
.
.

}


class HomeRepoRepository : IHomeRepository
{
    private VersionModel _version;

    VersionModel IHomeRepository.Version
    {
        get
        {
            if (_version == null)
            {
                var absoluteFileLocation = HttpContext.Current.Server.MapPath("~/App_Data/repo.txt");
                if (absoluteFileLocation != null)
                {           
                    _version = new VersionModel() //read the values from file (not shown here)
                    {
                        BuildNumber = "value from file",
                    };
                }
                else
                {
                    throw new Exception("path is null");
                }
            }
            return _version;
        }
    }
}



[Fact]
public void Version()
{
    // Arrange
    var repo = Substitute.For<IHomeRepository>();  //using Nsubstitute, but could be any mock framework
    repo.Version.Returns(new VersionModel
    {
       BuildNumber = "1.2.3.4",
    });

    HomeController controller = new HomeController(repo);  //pass in the mocked repository

    // Act
    ViewResult result = controller.Version() as ViewResult;
    var m = (VersionModel)result.Model;

    // Assert
    Assert.True(!string.IsNullOrEmpty(m.Changeset));
}
WhiskerBiscuit
  • 4,795
  • 8
  • 62
  • 100

1 Answers1

1

I believe you want test the real instantiation of IHomeRepository, which connects to a real database. In that case you need an App.config file, which specify the connection string. This is not a Unit test and it would an Integration Test. With HttpContext being null, you still can fake the HttpContext, retrieve real data from the database. See also here.

Community
  • 1
  • 1
Spock
  • 7,009
  • 1
  • 41
  • 60
  • My initial problem was reading the file correctly. Might I better off putting that code in a separate class with a file path parameter and then unit test that class? – WhiskerBiscuit Dec 08 '13 at 00:15
  • It depends on how you read the file. For example, what logic you have when you read the file. If it is not trivial, yes exactly what you said. Put the code in a separate class and it that operation as integration test. So you don't have to worry about HttpContext. If your file is simple enough, I would not worry about putting it into separate class and testing it. In that case your Unit Test would be sufficient. – Spock Dec 08 '13 at 00:48
  • Do you think this approach would be even better? http://stackoverflow.com/questions/8740498/how-to-unit-test-code-that-uses-hostingenvironment-mappath – WhiskerBiscuit Dec 08 '13 at 01:47
  • Yes, if you are writing a Unit Test, that's a sensible example. – Spock Dec 08 '13 at 01:56