2015-11-09 54 views
0

在當前的WPF應用程序中,我們需要在第一次使用時檢索用戶對象,然後在用戶使用該應用程序時只保留該用戶對象。單元測試通過公共屬性存儲庫的靜態類

我們打算用靜態方法做到這一點。

public static class UserHelper 
{ 
    public static User CurrentUser { get; set; } 
} 

但是,用戶數據保存在數據庫中。因此,我們將需要旋轉起來我們的資源庫的副本在這個輔助類做的工作:

public static class UserHelper 
{ 
    public static User CurrentUser { get; set; } 
    private static IRepository _rep = new Repository(); 

    public static void SetUser(string username) 
    { 
     CurrentUser = _rep.GetUserByName(username); 
    } 
} 

然而,這是不是可以進行單元測試 - 你不能在一個倉庫傳遞給一個靜態類,通過構造函數。因此最簡單的解決辦法似乎是使_rep公衆(和其重命名爲Rep) - 這樣你仍然可以把它作爲新Repository()在類,但在測試的時候,我們可以這樣做:

[TestMethod] 
public void Assert_SomethingAboutUsers 
{ 
    Mock<IRepository> repMock = new Mock<IRepository>(); 
    repMock.Setup(z => z.GetUserByName(It.IsAny<string>())).Returns(new User()); 
    UserHelper.Rep = repMock.Object; 

    // make assertions 
} 

但這對我來說很有趣。我覺得在靜態類中有一個倉庫是有點尷尬的。

這是一個壞主意嗎?如果是這樣,爲什麼?

回答

3

我認爲問題在於,在您的設計中,UserHelper的任務和功能的想法並不清楚。

如果你要描述一個UserHelper,你會說它只是從這個唯一的存儲庫中獲取信息,或者你會說用戶幫助器能夠與一個(可能很小的)存儲庫的範圍?

假設UserHelper僅用於此唯一存儲庫。在這種情況下,你的設計是這樣的,如果它使用不同的存儲庫,它將是一個不同的東西。因此單元測試使用自己的存儲庫是不正確的,因爲單元測試會測試你設計中的東西是不同的東西。

另一方面,如果你會說UserHelper應該能夠使用各種知識庫,那麼爲什麼你的類是靜態的?如果你的設計是這樣的,一個用戶助手可能與另一個倉庫一起工作,那麼在一個會話期間是否會有更多的用戶助手,或者只有一個?

如果你會說你的用戶助手的想法是可以同時存在多個用戶助手,那麼你的用戶助手不是單身人士,它不應該是靜態的。

如果您有一組有限的用戶幫助程序,並且事先知道可能會創建哪些用戶幫助程序,請考慮使用一個工廠,其中軟件用戶可以說:給我的用戶幫助程序,例如,用戶這個ID的助手,或者這個名字,或者使用這個倉庫,或者是一個對這個特定用戶來說很完美的UserHelper等。任何能夠唯一標識你想要的用戶助手的東西已經足夠了。

谷歌爲工廠設計模式

從你的描述

但是我有這個想法,在你的設計用戶助手應該支持各種信息庫(至少你的正常庫和一個特殊的單元測試庫) ,但在一次會話中只有一個用戶助手,稱爲THE ONE AND ONLY用戶助手。這個用戶幫助程序是爲了與給定的存儲庫一起工作,至少在命令做其他事情之前。

每當您的設計描述類似的類別的唯一實例時,人們往往會創建一個靜態類,而實際上他們需要一個單例。

Google for singleton design pattern。

MSDN about singleton

如果你覺得在你的眼睛,你的程序的一個會話期間只有一個用戶的幫手,每個人都應該用這一個用戶輔助對象,單身是這樣的:

public class UserHelper 
{ 
    private static UserHelper theOneAndOnlyInstance = null; 
    public static IRepository Repository {get; set;} 

    // private constructor, so no one can create an instance 
    private UserHelper() {} 

    // the function to get the one and only instance 
    public static UserHelper TheOneandOnlyUserHelper 
    { 
     get 
     { 
      if (theOneAndOnlyInstance == null) 
      { 
       theOneAndOnlyInstance = new UserHelper(); 
      } 
      return theOneAndOnlyInstance; 
     } 
    } 
} 

用法是:

public void InitializeProgram() 
{ 
    UserHelper.Repository = GetRepository(...); 
} 

public void MyFunction() 
{ 
    var userHelper = UserHelper.GetInstance() 
    userHelper.SetUser(...); 
} 

public void MyOtherFunction() 
{ 
    UserHelper.GetInstance().Function1(); 
} 

注意的GetInstance功能不是線程安全的。 Stackoverflow有幾個關於如何使線程安全的主題。

1

問題是,您的類正在測試對UserHelper有一個靜態依賴。靜態工具類是單元測試的主要敵人。特別是當他們從數據庫讀取繁重的工作時。

是否有沒有辦法讓UserHelper成爲一個非靜態類並將其注入到依賴實例?這樣你可以創建UserHelper的模擬代替。

除此之外,UserHelper是做兩件事情:它是從數據庫握住User對象,以提供給合作者讀取用戶。更好地從數據庫以外的UserHelper中讀取用戶,並將其僅指定給CurrentUser屬性。