Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing methods which use global variables

Lets say I have the following class structure:

private string GlobalVariable = "foo";

public void MainMethod()
{
    string bar = Baz();
}

public string Baz()
{
    return GlobalVariable + "qux";
}

I wish to carry out a unit test on Baz() using different values for GlobalVariable. However as GlobalVariable is simply called within the method, and not passed to it as a parameter, I cannot set this in my unit test method.

Therefore I've considered changing my structure to:

private string GlobalVariable = "foo";

public void MainMethod()
{
    string bar = Baz(GlobalVariable);
}

public string Baz(string globalVar)
{
    return globalVar + "qux";
}

This way I can now change the parameter value globalVar in my unit tests in order to check different outputs.

However, my first structure is more cleaner as I'm not unnecessarily passing variable values to methods as parameters.

Is there a way of getting the best of both worlds, without having to hinder my structure in order to run unit tests?

like image 472
Curtis Avatar asked Jul 01 '13 09:07

Curtis


2 Answers

I would be tempted to have a separate overloaded method, then I could have one with the parameter and one without...

public string Baz()
{
    return Baz(GlobalVariable);
}

public string Baz(string globalVar)
{
    return globalVar + "qux";
}

The benefit here is that you still have your parameter-less method which can be called from code without you having to worry about specifying the value each time, but then you have the overload for testing and also in the event you do ever need to use a different value.

Although you still cannot test the first method using different values, I think it would be safe to assume testing the second function only would be enough.


Or, if you are using C# 4.0 you could use optional parameters instead:

public string Baz(string globalVar = null)
{
    if(string.IsNullOrEmpty(globalVar))
        globalVar = GlobalVariable;
    return globalVar + "qux";
}
like image 149
musefan Avatar answered Oct 18 '22 05:10

musefan


If the global variable is immutable (like and application setting), I would not use an overload. Instead I would access the application setting in the testing code. So, I would leave it like this:

public string Baz()
{
    return ApplicationSetting.GlobalVariable + "qux";
}

then in the test I would do something like this:

[Test]
public void Test()
{
     string expected = ApplicationSetting.GlobalVariable + "qux";
     Assert.AreEqual(expected, Baz());
}

Then both the code under test and the test itself are using the same application setting source. This means that the source can change, but the test won't break. Hope this helps.

like image 27
Davin Tryon Avatar answered Oct 18 '22 06:10

Davin Tryon