Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying a private static readonly field

I have a large application that reads some parameters from a configuration file.

I'm writing unit tests for a class that generates a result after performing certain operations with both a parameter and a value read from the configuration file:

internal static class Password
{
    private static readonly byte PASSWORD_PRIVATE_KEY
        = ConfigFile.ReadByte("PASSWORD_PRIVATE_KEY");

    public static byte Generate(byte passwordPublicKey);
}

In my unit test, I know the values the Password.Generate() method should return for given PASSWORD_PRIVATE_KEYand PASSWORD_PUBLIC_KEY. But I'd like the PASSWORD_PRIVATE_KEY value used to be defined in the unit test class, not in the configuration file:

[TestMethod]
public void PasswordGenerate_CalculatedProperly()
{
    byte passwordPublicKey = 0x22;
    Password_Accessor.PASSWORD_PRIVATE_KEY = 0xF0;
    byte expectedGenerated = 0xAA;

    byte generated = Password_Accessor.Generate(passwordPublicKey);

    Assert.AreEqual(expectedGenerated, generated);
}

Is there a way I can write the private static readonly thru code, so I don't have to rely any configuration file for my tests?

like image 984
J.A.I.L. Avatar asked Oct 07 '13 16:10

J.A.I.L.


1 Answers

To do it in a clean way, you need to make Password more testable. To do this, consider this design:

internal static class Password
{
    public static void Configure(IPrivateKeyProvider keyProvider)
    {
        keyProvider = keyProvider;
    }

    public static byte Generate(byte passwordPublicKey); // use keyProvider

    private static IPrivateKeyProvider* keyProvider;
}

internal interface IPrivateKeyProvider
{
    byte GetPrivateKey();
}

internal class ConfigPrivateKeyProvider : IPrivateKeyProvider
{
    private static readonly byte PASSWORD_PRIVATE_KEY
         = ConfigFile.ReadByte("PASSWORD_PRIVATE_KEY");

    public byte GetPrivateKey()
    {
        return PASSWORD_PRIVATE_KEY;
    }
}

internal class PrivateKeyProviderStub : IPrivateKeyProvider
{
    public PrivateKeyProviderStub(byte privateKey)
    {
        this.privateKey = privateKey;
    }

    public byte GetPrivateKey()
    {
        return this.privateKey;
    }
}

Now your production code can use ConfigPrivateKeyProvider and tests can use the PrivateKeyProviderStub.

It is a bit simplified to retain Password as a static class. I'd recommend refactoring this also into an ordinary class, a singleton maybe if it's appropriate.

Note also that there are many testing frameworks that allow to generate mocks and stubs conveniently on the fly (Rhino Mocks for example), so there would be no need to manually implement PrivateKeyProviderStub.

like image 109
BartoszKP Avatar answered Oct 01 '22 22:10

BartoszKP