2013-01-22 92 views
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(这将是几乎相同的测试)

回答

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

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

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

  • 一般的单元测试应涵盖公共接口,而不是非公共成员和你GenerateHexString可能,如果它仅仅是通过其他方法
  • 你的实现是一样的,现在可以使用不应该是公共的,但他们未来可能会出现分歧。如果没有明显的测试用例,你可能会错过有人改变这些实现
  • 最终你的测试应该不知道或关心你的代码

一件事可能在NUnit的帮助的内部实现细节的一个介绍的重大更改将是TestCaseSource属性。它将允许您为这两种方法定义相同的测试用例,从而在代码中保存一些重复内容。

+0

真正伟大的答案。这有很大帮助。 – user1520312

+0

如果我要为GenerateKey和GenerateSecret使用一个函数。我会称这种功能是什么? GenerateKeyOrSecret? – user1520312

+0

还有一个问题。如果您查看GenerateKey_keys_are_random,是否会破坏单元测试的规则必须是确定性的。由于一个以上的密钥可能相同,所以非常不可能。 – user1520312