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

为什么需要两种做同样事情的方法?

无论如何,您应该编写单独的测试。

  • 通常单元测试应该覆盖公共接口而不是非公共成员,如果它只被其他方法使用,你的 GenerateHexString 可能不应该是公共的
  • 您的实现现在是相同的,但将来它们可能会有所不同。如果没有不同的测试用例,您可能会错过由更改其中一种实现的人引入的重大更改
  • 最终你的测试不应该知道或关心你的代码的内部实现细节

在 nUnit 中可能有帮助的一件事是 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 回答