2012-10-24 70 views
2

如果您需要從另一個項目中測試非公共屬性,Microsoft單元測試嚮導會創建Accessor對象。在我的單元測試中,我創建了輔助函數,這樣我就不會在每個單元測試方法中重複相同的代碼。目前我有兩個幾乎完全相同的測試,除了一個採用標準公共對象,另一個採用Accessor版本。由於Accessor基於公共對象,所以我應該能夠擁有一個功能。我曾假設我可以使用泛型來完成一個簡單的演員。但在posting the question之後,我發現還有很多工作要做,包括必須更新底層對象。我的問題是另一種方法來減少這些冗餘方法只有一個功能使用鑄造(或其他)的方法?最佳方式更新使用共享函數的兩個常用函數

下面是現有的兩個功能:

// Common function to create a new test record with standard Account object 
internal static void CreateAccount(out Account account, bool saveToDatabase) 
{ 
    DateTime created = DateTime.Now; 
    string createdBy = _testUserName; 

    account = new Account(created, createdBy); 

    account.Notes = Utilities.RandomString(1000); 

    if (saveToDatabase) 
     account.Create(); 
} 

// Common function to create a new test record with Account_Accessor 
internal static void CreateAccount(out Account_Accessor account, bool saveToDatabase) 
{ 
    DateTime created = DateTime.Now; 
    string createdBy = _testUserName; 

    account = new Account_Accessor(created, createdBy); 

    account.Notes = Utilities.RandomString(1000); 

    if (saveToDatabase) 
     account.Create(); 
} 

我有這些單元測試的兩打和真實對象有10個屬性的平均值,我在這裏簡單的例子。

下面是單元測試API創建的訪問器代碼(再次,我已經降低下來,以簡化的例子):

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System; 
using System.Collections.ObjectModel; 
using System.Data; 

namespace NameHere.Bll 
{ 
    [Shadowing("NameHere.Bll.Account")] 
    public class Account_Accessor : ProjectBase_Accessor<Account> 
    { 
     protected static PrivateType m_privateType; 

     public Account_Accessor(PrivateObject value); 
     [Shadowing("[email protected]")] 
     public Account_Accessor(DateTime created, string createdBy); 

     [Shadowing("_notes")] 
     public string _notes { get; set; } 

     public static Account_Accessor AttachShadow(object value); 

     [Shadowing("[email protected]")] 
     public override void Create(); 
    } 
} 

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System; 
using System.ComponentModel; 
using System.Linq.Expressions; 

namespace NameHere.Bll 
{ 
    [Shadowing("NameHere.Bll.ProjectBase`1")] 
    public class ProjectBase_Accessor<T> : BaseShadow, INotifyPropertyChanged 
    { 
     protected static PrivateType m_privateType; 

     public ProjectBase_Accessor(PrivateObject value); 

     [Shadowing("Created")] 
     public DateTime Created { get; set; } 
     public static PrivateType ShadowedType { get; } 

     [Shadowing("[email protected]")] 
     public void add_PropertyChanged(PropertyChangedEventHandler value); 
     public static ProjectBase_Accessor<T> AttachShadow(object value); 

     [Shadowing("[email protected]")] 
     public virtual void Create(); 
    } 
} 
+0

'Account'和'Account_Accessor'之間的區別是什麼? –

+0

無視我的答案。因爲這顯然與你的其他問題的答案完全相同。 http://stackoverflow.com/a/12998986/2009。換句話說,我認爲泛型實際上是你用最少的工作量來完成的方法。 – hometoast

+0

我在我的問題中添加了代碼訪問器代碼,正如@dthorpe指出的那樣,Accessor繼承自BaseShadow(在它通過我們的Base類之後)。 – Josh

回答

3

的問題是,即使訪問類公開相同的方法和屬性作爲它所隱藏的類,訪問器和原始類之間沒有共同的接口。 Account_Accessor從BaseShadow繼承,Account從其他繼承。就編譯器而言,它們是完全不相關的類型,而不是賦值兼容的,所以很難將它們的實例傳遞給一個普通的例程。

如果您可以強制Account_Accessor類實現也由Account實現的接口類型,那麼您可以將每個接口的實例傳遞給將接口類型作爲參數的函數。就像這樣:

internal static IAccount SetupAccount(IAccount account, bool saveToDatabase) 
{ 
// do account setup here - not construction 
} 

// to call: construct instance, then pass to common function 
var account = new Account(a, b); 
SetupAccount(account, true); 

如果客戶實例的結構是足夠複雜,你希望有一個共同的例行太,把特定類型的包裝在公共功能的面前:

internal static IAccount CreateAccount(bool saveToDatabase) 
{ 
    var account = new Account(a,b); 
    return SetupAccount(account, saveToDatabase); 
} 

internal static IAccount CreateAccountAccessor(bool saveToDatabase) 
{ 
    var account = new Account_Accessor(a,b); 
    return SetupAccount(account, saveToDatabase); 
} 

你不能逃避的一點是:某個地方的某個人必須承諾要構建哪個實例。即使你把它歸結爲傳遞類型並使用Activator.CreateInstance(),但有人必須承諾選擇使用哪種類型。

一旦構造實例並且兩種類型都實現了通用接口,那麼所有常用函數需要關心的是通用接口。

+0

感謝細節。如果我們傳遞一個對象並嘗試轉換爲Account或Account_Accessor,因爲這兩個對象不是從同一個源繼承的,我假設我們有同樣的問題。 – Josh

+0

正確。您可以使參數類型爲Object,但要進行方法調用,您必須將該對象轉換爲特定類型(Account或Account_Accessor)。由於這兩種類型不相關,這意味着每次您的通用代碼想要對該對象執行某些操作時,您都必須分支/擁有一條if語句。可能不值得麻煩。 – dthorpe

+0

前衛的可能性可能是嘗試在常規例程中使用動態對象。動態對象是類似JavaScript工作方式的後期綁定類型。理論上,這意味着在對象上找到一個「foo」方法不會在編譯時發生,它發生在運行時,所以無論涉及哪個對象實例,它都可能在運行時發現相同名稱的方法。我並不熟悉動態來提供實施建議,但可能值得研究。 – dthorpe

相關問題