Question

I have a Client class which accepts an object with IConfiguration interface in the constructor.

Configuration should be validated when Client object is created.

public interface IConfiguration
{
    int ReconnectDelay { get; }
}

public class Client
{
    public Client(IConfiguration configuration)
    {
        if (configuration.ReconnectDelay < 60000)
        {
            throw new ConfigurationErrorsException();
        }
    }
}

For testing purposes I need a client with ReconnectDelay property set to a value which is less than valid.

Here's my current solution:

public class Client
{
    public Client(IConfiguration configuration)
    {
        ValidateConfiguration(configuration);
    }

    protected virtual void ValidateConfiguration(IConfiguration configuration)
    {
        if (configuration.ReconnectDelay < 60000)
        {
            throw new ConfigurationErrorsException();
        }
    }
}

public class TestClient : Client
{
    public TestClient(IConfiguration configuration)
        : base(configuration)
    {
    }

    protected override void ValidateConfiguration(IConfiguration configuration)
    {
    }
}

It works, but causes call to virtual method in constructor, which is bad (I know that right now it will do no harm, but I want to fix this anyway).

So, is there any elegant solution for this?

Was it helpful?

Solution

You can make a Validator interface with 2 implementations and then delegate to the validator. Technically, this is still a virtual call but its to another object so you don't have to worry about subclasses of Client overriding the call or accessing the partially built Client.

public interface IValidator
{
    bool Validate (IConfiguration configuration);
}

Then your normal usecase uses a ReconnectionValidator.

public class ReconnectionValidator : IValidator
{

     bool Validate (IConfiguration configuration)
     {
       return configuration.ReconnectDelay >= 60000;
     }
}

Your test Validator can always return true

public class NullValidator : IValidator
{

     bool Validate (IConfiguration configuration)
     {
       return true;
     }
}

Your Client code would then take both the IValidator and an IConfiguration in its constructor and test if the validator validates the configuration.

public Client(IConfiguration configuration, IValidator validator)
{
   if(!validator.Validate(configuration))
   {
        throw new ConfigurationErrorsException();
    }
}

The bonus of this technique is you can change the validator later or have a new implementation that chains several validators together to support "or"ing and "anding" validators together.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top