2012-06-03 31 views
3

我注意到,爲了在我的OO代碼中對每個單元進行單元測試,我需要將訪問修飾符設置爲public,即使應該保護或可能是私有的方法。這可以練習嗎?OO中的單元測試和訪問修飾符

public class EnforceBusinessRules 
{ 
    BusinessState m_state; 

    public EnforceBusinessRules() 
    { 
     m_state = START; 
    } 


    public bool isInputcurrentlyFormatted(string input) 
    { 
     //code goes here to ensure the input passes formatting test 
     //modify m_state appropriately 
    } 


    public bool InputContainsValidStartAndEndTokens(string input) 
    { 
     //code goes here to ensure that the start and end tokens of the input are of the type available in the system 
     //modify m_state appropriately 
    } 


    public bool StartEndCommandisValidAccordingtoCurrentSystemSettings(string input) 
    { 
     //code goes here to check the start and End codes match the current start and end codes for the day 
     //modify m_state appropriately 
    } 

    // and so on 
} 
+4

可能不是。爲什麼你需要直接測試私有方法(即不屬於你的API的方法)?如果它們足夠複雜以至於需要單獨測試,那麼可能有一種觀點認爲應將此行爲分解爲一​​個單獨的類別...... –

+0

通過發佈您已在代碼中完成的內容,可以改進此問題。 –

回答

5

單元測試是「黑匣子」測試。您應該只測試外部可見元素。如果你測試所有的內部工作,那麼你不能正確地重構你的代碼而不修改所有的單元測試。

+1

+1該死的 - 比我的更好! –

+0

所以你說可以不直接單元測試我想保持私人的方法嗎? – Kobojunkie

+0

是的。重點是什麼?如果你的公共方法返回正確的值,你可以推斷你的私有方法也返回正確的值。此外,它允許您在不更改測試的情況下更改這些私有方法。如果他們錯了,他們也應該打破公共實現 – Liam

0

不可以。您在我看來是錯誤地思考它。你可以在不公開事物的情況下推斷事物。例如,一個屬性的值可以通過函數返回來實現。

在受保護成員的情況下。問你自己這是什麼意思。這意味着派生類可以訪問該成員。所以在測試中做一個派生類型。

1

如果您發現需要更改訪問修飾符,因爲您需要測試私有成員中的大量代碼,這可能表示您的類太大。考慮將您想要測試的行爲打破成可以測試的具有公共接口的較小類。你的代碼可能會受到代碼味道的影響。

請記住,受保護的成員與公共成員非常相似,但可能的客戶端空間要小得多(僅派生類)。您可以考慮通過創建只有您的測試使用的派生對象來對這些方法進行單元測試。通過這種方式,您將以與您的客戶使用它們相同的方式來測試這些方法。

這裏是您可能修改代碼的一種方法:

public class EnforceBusinessRules 
{ 
    BusinessState m_state; 

    public EnforceBusinessRules(IEnumerable<Rule> rules) 
    { 
     m_state = START; 
    } 

    public void Enforce(string input) 
    { 
     foreach (var rule in rules) 
     { 
      m_state = rule.EnforceRule(input); 
     } 
    } 
} 

public interface Rule 
{ 
    public BusinessState EnforceRule(string input); 
} 

public class IsInputcurrentlyFormatted : Rule 
{ 
    public BusinessState EnforceRule(string input) 
    { 
     //code goes here to ensure the input passes formatting test 
    } 
} 

public class InputContainsValidStartAndEndTokens : Rule 
{ 
    public BusinessState EnforceRule(string input) 
    { 
     //code goes here to ensure the input passes formatting test 
    } 
} 

public class StartEndCommandisValidAccordingtoCurrentSystemSettings : Rule 
{ 
    public BusinessState EnforceRule(string input) 
    { 
     //code goes here to ensure the input passes formatting test 
    } 
} 

// and so on 
+0

那麼,我有很多私人方法,因爲在處理輸入時,我必須考慮這麼多條件。在給出18的輸入後,我有大約20條規則來確保申請通過輸入。 – Kobojunkie

+0

@Kobojunkie創建一個處理輸入的內部類。 –

+0

爲每個規則創建一個班級甚至可能是值得的。那麼如果這些規則需要在不同的上下文中使用,它們將被完全測試,而不依賴於驅動它們的當前代碼。 –

0

通常是不好的做法,公開方法/類/屬性/不管到外面的世界,你不希望暴露。我的工作遇到了類似的問題。我們編寫了測試公共方法和屬性,因爲這些公共方法在某些時候應該調用所有的私有方法。在具有內部類/屬性/方法的情況下,您可以使用InternalsVisableTo屬性來訪問您的單元測試庫。

[assembly: InternalsVisibleTo("AssemblyB")] 

http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx

+0

這通常是一個壞主意。它確實讓你解決了這個問題,而且我自己也是這樣做的,但是應該儘可能地避免 – Liam

0

這聽起來像你的失敗,使您的私人數據是正確的encapsulated創建getter和setter方法。

單元測試應該通過getters和setter訪問數據。

避免在類代碼中實例化協作對象inject those dependencies

+1

這些代表我的過程的各個步驟的方法。我決定分解它,這樣我就可以將步驟分成單元。 – Kobojunkie

0

如果您需要測試私有或受保護的屬性或方法,那麼您應該將功能提取到不同的類中。每個班級只應做一件事(單一職責原則)。可能性是您的私人方法在您班級的主要目的上執行輔助功能。

提取時,會發生兩件好事:首先,您希望測試的代碼現在可以通過單元測試完全訪問。其次,您不必在EnforceBusinessRules類中擔心它。