5

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?

4

4 回答 4

7

要以干净的方式进行,您需要使其Password更具可测试性。为此,请考虑以下设计:

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;
    }
}

现在您的生产代码可以使用ConfigPrivateKeyProvider并且测试可以使用PrivateKeyProviderStub.

Password保留为静态类有点简化。我建议将它也重构为一个普通的类,如果合适的话,可能是一个单例。

另请注意,有许多测试框架可以方便地即时生成模拟和存根(例如Rhino Mocks),因此无需手动实现PrivateKeyProviderStub.

于 2013-10-07T16:25:43.520 回答
2

我不是 .NET 专家,所以对此持保留态度。

单元测试的价值之一是向您展示您需要重新考虑您的代码。如果很难测试,则需要重写。

找出一种将文件的抽象注入 的方法Password,然后创建该抽象的模拟实现(例如,使用MoqRhino Mocks)。

但是正如您现在拥有的那样,我认为没有任何方法可以使用文件。您只需要告诉您的测试查看不同的文件即可。

希望有帮助。

于 2013-10-07T16:29:18.663 回答
1

不,没有办法访问私有字段。

对于单元测试,您通常希望访问内部内容,您可以使用InternalsVisibleTo来实现。但即使有私人成员也保持私密。您可能希望为这些字段定义一个 getter。

编辑:使用有点繁琐的语法,您可以使用PrivateObjects访问私有字段。

于 2013-10-07T16:20:40.667 回答
1

如果您真的想更改私有静态只读,您仍然可以使用反射来执行此操作,如下所示:

 typeof(YourClassName).GetField("YourStaticReadonlyMemberName", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, YouModifiedObject);

例如:

 typeof(FileSystemService).GetField("proofedStatic", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, mockedProofedClass);

我同意它几乎不应该被使用,但有时如果你别无选择,你有办法做到这一点。

于 2018-07-17T07:43:31.133 回答