修改私有静态只读字段

时间:2013-10-07 16:13:44

标签: c# unit-testing

我有一个大型应用程序,它从配置文件中读取一些参数。

我正在为一个类编写单元测试,该类在使用参数和从配置文件中读取的值执行某些操作后生成结果:

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

    public static byte Generate(byte passwordPublicKey);
}

在我的单元测试中,我知道Password.Generate()方法应该为给定的PASSWORD_PRIVATE_KEYPASSWORD_PUBLIC_KEY返回的值。但是我想在单元测试类中定义PASSWORD_PRIVATE_KEY值,而不是在配置文件中定义:

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

有没有办法可以编写private static readonly代码,所以我不必依赖任何配置文件进行测试?

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

我不是.NET专家,所以请耐心等待。

单元测试的一个值是向您显示需要重新考虑代码。如果难以测试,则需要重写。

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

但是现在你已经拥有了,我认为没有办法使用文件。你只需要告诉你的测试来看一个不同的文件。

希望有所帮助。

答案 2 :(得分:1)

没有。 无法访问私人领域。

对于单元测试,您通常希望访问内部资源,并且可以使用InternalsVisibleTo执行此操作。但即使私人成员保持私密。您可能希望为这些字段定义一个getter。

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

答案 3 :(得分:1)

如果您确实要更改私有静态只读,则仍然可以使用反射进行如下操作:

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

例如:

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

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