Kelso Sharp Kelso Sharp - 2 months ago 10
C# Question

When working base and derived classes what is the best way to deal with AppSettings, that will allow for testability

I hope this is decent question, the background is that I have an abstract base class, this base class has some concrete method implementations which are accessible to derived classes. The base class and the all of the derived classes have a set of unique variables. All of the common functionality is in the concrete methods of the base class (Which are NOT virtual so they cannot be overridden) Each of the derived classes are also getting some of these values from the AppSettings in the App.Config file.

So my question is this, Where is the best place to put these const values that would be following best practices and will allow the code to be properly testable (this last piece is very important)?

The 2 options that I know are:

1) Create a static config class that has all of the values for each of the classes. This is great for the normal consts, but retrieving the App.Config values will fail unless, either the Test project has the values in its own App.Config file (This seems like a dirty hack to me)

2) The other option is to declare them and get the values settings in the using class, this adheres to the declare it where you use it principle, but it makes the class un-testable unless you again add the values to the App.Config of the test project.

public abstract class BaseClassA
{

private const string PATH = "\ParentClassPath\" // Option 2
private int _var1;
private string _var2;
public BaseClassA(int param1, string param2)
{
_var1 = param1;
_var2 = param2;
}
public int Param1Prop { get; private set;}
public string Param2Prop { get; private set; }

protected string Method1(string value1, string value2, string value3)
{
Directory.CreateDirectory(StaticClass.PATH); //Option 1
return Path.GetDirectoryName(PATH) //Option 2
}
}

public class DerivedClassB
: base(1, "param2")
{

private const string PATH = "\DerivedClassPath\" // Option 2

public BaseClassA(int param1, string param2)
{
_var1 = param1;
_var2 = param2;
}
public int Param1Prop { get; private set;}
public string Param2Prop { get; private set; }

protected string Method1(string value1, string value2, string value3)
{
Directory.CreateDirectory(StaticClass.DERIVED_PATH); //Option 1
return Path.GetDirectoryName(PATH) //Option 2
}
}

Answer

Create a custom class that wraps your call to ConfigurationManager.AppSettings["key"] with an interface. Mock that interface in your test so that you can define which values you need to test. Rough example to explain (untested):

public interface IConfigurationService
{
    string Get(string key);
}


public class ConfigurationService :IConfigurationService
{
    public string Get(string key)
    {
        return ConfigurationManager.AppSettings[key];
    }
}

In your tests you can now mock your interface as such:

public void NaiveTest()
{
    var key = "someKey";
    var result = "someValue";
    var mockConfigurationService = new Mock<IConfigurationService>();
    mockConfigurationService.Setup(x => x.Get(key)).Returns(result);

   // pass service to class being tested and continue
}

Include your configuration service in your base class, then each derived class can pull their values as needed. You can now test any value you like through the use of Mocks. More here: https://github.com/moq/moq4

Please let me know if you need further advice.

Comments