2013-01-22 126 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