2012-01-23 25 views
2

不知道我需要在這裏做什麼。我有私人的方法,使數據庫調用回顧價值觀,然後返回值給調用者。我看過Moq,但我不太確定那就是我需要的。無法理解如何測試一些東西

我的方法之一的一個例子是這樣的:

private bool ClientIdMatchesUserId(int userId, Guid clientId, out string message) 
    { 
     bool idsMatch; 

     const string sql = "sql goes here"; 

     int result = (int)SqlHelper.ExecuteScalar(Connection, CommandType.Text, sql); 
     if (result != 1) 
     { 
      idsMatch = false; 
      message = "ClientId does not match."; 
     } 
     else 
     { 
      idsMatch = true; 
      message = "ClientId matches."; 
     } 

     return idsMatch; 
    } 

使這個混亂對我來說是1)我有一個私人的方法和2)具有輸出參數的事情。

Moq是我需要的嗎?我是否需要創建一個具有已知值的測試數據庫?

我要補充一點,我是新來的測試,並可以使用所有的意見,我可以得到;)

回答

3

爲單元測試類的設計,你需要從業務邏輯數據庫的訪問分開。在這一點上,您可以嘲笑依賴關係並通過其公共接口測試該類。

下面是一個如何實現的例子。然後

public class User 
{ 
    // properties map to columns 
    // Consider using NHibernate, Entity Framework, etc. 
} 

// ALL database access goes through interface implementations. 
public interface IUserRepository 
{ 
    // One of several options - TryParse pattern 
    bool TryGetById(int userId, out User user); 
} 

public class SomeBusinessLogic 
{ 
    public SomeBusinessLogic(IUserRepository userRepository) 
    { 
     _userRepository = userRepository; 
    } 

    public string ValidateClient(int userId) 
    { 
     // Probably more logic here. 
     string message; 
     bool result = ClientIdMatchesUserId(userId, out message); 

     if (result) 
     { 
      return string.Empty; 
     } 

     return message; 
    } 

    private bool ClientIdMatchesUserId(int userId, out string message) 
    { 
     User user; 
     bool found = _userRepository.TryGetById(userId, out user); 

     message = 
      found 
      ? "ClientId matches." 
      : "ClientId does not match."; 

     return found; 
    } 

    private readonly IUserRepository _userRepository; 
} 

你的測試將是這個樣子:

[Test] 
public void ValidateClient_WhenValid_ReturnsEmptyString() 
{ 
    // Arrange 
    const int UserId = 1234; 
    var mockRepo = new Mock<IUserRepository>(); 
    var user = new User(); 
    mockRepo.Setup(x => x.TryGetById(UserId, out user)).Returns(true); 
    var sut = new SomeBusinessLogic(mockRepo.Object); 

    // Act 
    string result = sut.ValidateClient(UserId); 

    // Assert 
    Assert.That(result, Is.EqualTo(string.Empty)); 
} 

[Test] 
public void ValidateClient_WhenInvalid_ReturnsMessage() 
{ 
    // Arrange 
    var mockRepo = new Mock<IUserRepository>(); 
    var sut = new SomeBusinessLogic(mockRepo.Object); 

    // Act 
    string result = sut.ValidateClient(1234); 

    // Assert 
    Assert.That(result, Is.EqualTo("ClientId does not match.")); 
} 

我建議你閱讀The Art of Unit Testing with Examples in .NET得到更好的理解這一點。這是一個複雜的話題。

+1

+1。完全同意。 BTW @ user1064763,您的數據庫訪問現在將存在於實現「IUserRepository」的類中,您可以使用集成測試對測試數據庫進行測試。 – Ergwun

+0

@Ergwun - 確切地說。 – TrueWill

0

我會找痣。 http://research.microsoft.com/en-us/projects/pex/downloads.aspx

Moq的用於那些公共類使用默認構造函數和虛擬方法模擬接口依賴關係或相關性。痣讓你嘲笑基本上什麼,是專爲嘲諷外部依賴性如數據庫,文件等

+3

我還要補充一點,這一般不測試的私有方法中最好的做法 - 你想測試你的類的公共接口。如果你有很多私人方法你很難進行測試,這很好地表明你可能想要將它們拉到一個單獨的課堂並讓它們公開,給你的原始課程一個私人蔘考給你的新課程類。 –

+0

有趣。但是,如果我不應該測試代碼的較低級別,那麼我現在對單元測試提供的值有點困惑。我的大多數私有方法都封裝了最終用戶不應該看到的功能(如業務邏輯)或簡單地說是繁重的工作。再說一遍,也許我對結構化的想法是不正確的。 我現在要查看該鏈接。非常感謝。 – user1064763

+0

單元測試用於測試你的單獨的類 - 如果你有一個帶有公共方法「Add(int x,int y)」的「Adder」類,你會測試添加2和5給你回7.測試類型您所描述的是「系統」或「集成」測試 - 測試您的代碼是否與某個外部實體正確交互。您可以通過拆分課程來提供接縫進行測試,而無需將所有接縫暴露給最終用戶。 –

相關問題