2

I have a method that uses Application variables to get information from an external file. Since Application variables are not used in unit tests, is there a way I can get the Application variables values from my Global.asax file and be able to use them in the test?

This is my test method:

[TestMethod]
public void TestGetCompanyList()
{
    var accController = new AccSerController();
    CInt cInt = new CInt();
    cIn.Iss = "Other";
    cIn.Tick = "BK";
    var result
      = accController.Clist(cIn) as IEnumerable<CList>;
    Assert.IsNotNull(result);
}
6
  • follow this stackoverflow.com/questions/12023517/… or haacked.com/archive/2005/06/11/simulating_httpcontext.aspx Commented Mar 2, 2015 at 16:06
  • i seen the first link, but couldnt really follow along (im new to this). Looking at the second link right now. Commented Mar 2, 2015 at 16:10
  • How are you loading the application variable? Commented Mar 2, 2015 at 16:16
  • Don't use the application variable for this. Use the repository pattern. Your web pages/controllers shouldn't need to know the details of the repository, just the interface. Then you can use a different implementation of the repository for your unit tests. Commented Mar 2, 2015 at 16:22
  • @mason What is a repository pattern? that is the first time i am hearing about that. Where can i learn more about it. Commented Mar 2, 2015 at 16:37

3 Answers 3

2

Use the repository pattern. Your controller shouldn't have any idea about WebConfiguration.

//This defines the stuff that your controller needs (that your repository should contain)
public interface ISiteConfiguration
{
    string Setting1 {get; set;}
}

//Use this in your site. Pull configuration from external file
public class WebConfiguration : ISiteConfiguration
{
    public string Setting1 {get; set;}

    public WebConfiguration()
    {
        //Read info from external file here and store in Setting1
        Setting1 = File.ReadAllText(HttpContext.Current.Server.MapPath("~/config.txt"));
    }
}

//Use this in your unit tests. Manually specify Setting1 as part of "Arrange" step in unit test. You can then use this to test the controller.
public class TestConfiguration : ISiteConfiguration
{
    public string Setting1 {get; set;}
}

I'm using Ninject to perform dependency injection, but there's lots of other libraries out there. I'm going to omit some basic Ninject setup from my answer, because there's plenty of resources out there. But the below code shows how you'd specify in your web application to use WebConfiguration to fulfill the needs of an ISiteConfiguration.

private static void RegisterServices(IKernel kernel)  
{
    kernel.Bind<ISiteConfiguration>().To<WebConfiguration>();
}

Here's where the magic happens. When an instance of your controller is created in your web application, Ninject will look at the constructor and see that it's asking for ISiteConfiguration. And in your Ninject configuration, you told it to use WebConfiguration when it needs ISiteConfiguration. So Ninject will create a new instance of WebConfiguration and provide (inject) it to your controller.

public class AccountServiceController
{
    ISiteConfiguration Config {get; set;}

    //This is called constructor injection
    public AccountServiceController(ISiteConfiguration config)
    {
        Config = config;
    }

    public ActionResult Index()
    {
        //Now you can use Config without needing to know about ISiteConfiguration's implementation details
        //Get settings from Config instead of Application
    } 
}

You can also use Ninject in unit testing, but here's a simpler demo where we're not using it:

[TestMethod]
public void TestGetCompanyList()
{
    //Arrange
    var config = new TestConfiguration(){ Setting1 = "mysetting" };
    var accountController = new AccountServiceController(config);
}

The result of all this is that you can use your controller's action methods easily for unit testing, because you can use whatever implementation of ISiteConfiguration you want.

Sign up to request clarification or add additional context in comments.

Comments

0

I've done the following on some of my tests. Not ideal but it gets the job done.

if (System.Web.HttpContext.Current != null)
{
     //   Fill your application variable
}
else
{
     //   Get your data from somewhere else                    
}

Comments

0

There are two ways of unit testing such scenarios as far as I know.

First one is based on splitting controller function into two: one is controller function itself, another one implements the logic (e.g.: this is the one you test). Example:

Before:

public void MyControllerFunction()
{
    var x = Context["variable"];
    do-something-with-x;
}

After:

public void MyControllerFunction()
{
    var x = Context["variable"];
    MyControllerLogic(x);
}

internal void MyControllerLogic(object x)
{
    do-something-with-x;
}

And then you test MyControllerLogic() function instead of MyControllerFunction() in unit test

Another methodology is create a surrogate context before invoking unit test.

Example:

var controller = new MyController();
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
controller.Request.Content = new StringContent("{ x: 21 }",
     Encoding.Unicode);
controller.Request.Content.Headers.ContentType.MediaType =
     "application/json";

Please note, I did not create HttpContext in 2nd example, I'm not sure if it's a requirement to have. You probably should be able to create it in similar way as well as the other variables you use. It's sort of a hack anyway, so treat it as such

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.