2

私は次のクラスを持っています

public interface IAuthProvider
{
    string GenerateKey();
}

public class AuthProvider : IAuthProvider
{
    public string GenerateKey()
    {
        using (var rng = new RNGCryptoServiceProvider())
        {
            var data = new byte[16];
            rng.GetBytes(data);
            return BitConverter.ToString(data).Replace("-","");
        }
    }
}

それに付随する次の単体テストもあります

[TestClass]
public class AuthProviderTests
{
    private AuthProvider _provider;
    private string _key;

    [TestInitialize]
    public void Initialize()
    {
        _provider = new AuthProvider();
        _key = _provider.GenerateKey();
    }

    [TestMethod]
    public void GenerateKey_key_length_is_32_characters()
    {
        Assert.AreEqual(32, _key.Length);
    }

    [TestMethod]
    public void GenerateKey_key_is_valid_uppercase_hexidecimal_string()
    {
        Assert.IsTrue(_key.All(c =>
            (c >= '0' && c <= '9') || 
            (c >= 'A' && c <= 'F')
        ));
    }

    [TestMethod]
    public void GenerateKey_keys_are_random()
    {
        var keys = new List<string>
            {
                _provider.GenerateKey(),
                _provider.GenerateKey(),
                _provider.GenerateKey(),
                _provider.GenerateKey(),
                _provider.GenerateKey()
            };

        var distinctCount = keys.Distinct().Count();

        Assert.AreEqual(5, distinctCount);
    }
}

すべてがうまく機能します。ただし、GenerateSecret というメソッド (およびそれに付随するテスト) を作成する必要があります。このメソッドは、GenerateKey() とまったく同じことを行います。

今、GenerateRandomHexString(int bytes) というメソッドを作成し、GenerateKey からコードをコピーする必要があると考えています。次に、GenerateKey と GenerateSecret については、次のコードを使用する必要があります。

public interface IAuthProvider
{
    string GenerateKey();
    string GenerateSecret();
    string GenerateRandomHexString(int bytes);
}

public class AuthProvider : IAuthProvider
{
    public string GenerateKey()
    {
        return GenerateRandomHexString(16);
    }

    public string GenerateSecret()
    {
        return GenerateRandomHexString(16);
    }

    public string GenerateRandomHexString(int bytes)
    {
        using (var rng = new RNGCryptoServiceProvider())
        {
            var data = new byte[bytes];
            rng.GetBytes(data);
            return BitConverter.ToString(data).Replace("-","");
        }
    }
}

テストについては、GenerateRandomHexString メソッドのテストだけを作成するか、GenerateSecret と GenerateKey のテストも作成する必要があります (ほとんど同じテストになります)。

4

2 に答える 2

2

なぜ同じことをする 2 つのメソッドが必要なのですか?

とにかく、個別のテストを作成する必要があります。

  • 通常、単体テストは非パブリック メンバーではなくパブリック インターフェイスをカバーする必要があり、GenerateHexString が他のメソッドによってのみ使用される場合は、おそらくパブリックであってはなりません。
  • 実装は現在同じですが、将来的には異なる可能性があります。明確なテスト ケースがないと、誰かがそれらの実装の 1 つを変更することによって導入された重大な変更を見逃す可能性があります。
  • 最終的に、テストはコードの内部実装の詳細を認識したり気にしたりすべきではありません

nUnit で役立つ可能性のあるものの 1 つは、TestCaseSource 属性です。両方のメソッドに対して同じテスト ケースを定義できるため、コードの重複を抑えることができます。

于 2013-01-22T00:57:33.713 に答える
0

同じことを行うために多くのインターフェースメソッドを作成するのは悪い考えです。また、インターフェイスにオーバーロードをかけません。これが引き起こす問題は、同じセマンティックな意味を持つメソッドが非常に異なる実装を持つ可能性があることです。最も単純なケースではないかもしれませんが、単純なケースは最終的に複雑なケースになることがよくあります。

この問題の拡張メソッドが大好きです。

public interface IAuthProvider
{
    string GenerateKey();
}

public static class IAuthProviderExtensions
{
    public static string GenerateSecret(this IAuthProvider provider)
    {
         return provider.GenerateKey();
    }
}

テスト:

[Test]
public void GenerateSecretIsAliasForGenerateKey()
{
    var mockProvider = new Mock<IAuthProvider>();
    var key = GenerateARandomStringSomehow();
    mockProvider.Setup(p=>p.GenerateKey()).Returns(key);
    Assert.That(mockProvider.Object.GenerateSecret(), Is.EqualTo(key));
}
于 2013-01-22T04:07:50.433 に答える