重复单元测试好吗?

时间:2013-01-22 00:47:41

标签: c# unit-testing

我有以下课程

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编写测试(这将是完全相同的测试)

2 个答案:

答案 0 :(得分:2)

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

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

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

在nUnit中可能有用的一件事就是TestCaseSource属性。它允许您为两种方法定义相同的测试用例,从而在代码中保存一些重复。

答案 1 :(得分: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));
}