2010-09-16 91 views
8

我想在Visual Studio 2010中的當前項目上開始使用單元測試。但是,我的類結構包含一些接口和抽象類繼承關係。單元測試抽象類和或接口

如果兩個類是從同一個抽象類或接口派生的,我希望能夠在它們之間共享測試代碼。我不確定如何完全做到這一點。我在考慮爲每個要測試的接口創建一個測試類,但我不確定將具體類提供給適用單元測試的正確方法。


更新

確定這裏是一個例子。假設我有一個接口IEmployee,它由抽象類Employee實現,然後由兩個具體類Worker和Employee繼承。 (代碼如下所示)

現在說我想創建適用於所有IEmployees或Employees的測試。或者,爲特定類型的員工創建特定測試。例如,我可能想要斷言將IEmployee.Number設置爲一個小於零的數字,任何IEmployee實現都會拋出異常。我更願意從任何IEmployee的角度編寫測試,然後能夠在任何IEmployee實現上使用測試。

這是另一個例子。我可能還想斷言,將任何員工的休假時間設置爲小於零的錯誤和誤差。但是我也可能想要應用於特定具體版本的員工的不同測試。說我想測試工人拋出,如果他們提供了更多的則14天度假的例外,但可以提供一個經理高達36

public interface IEmployee 
{ 
    string Name {get; set;} 
    int Number {get; set;} 
} 


public abstract class Employee:IEmploee 
{ 
    string Name {get; set;} 
    int Number {get;set;} 
    public abstract int VacationTime(get; set;) 
} 


public abstract class Worker:IEmployee 
{ 
    private int v; 

    private int vTime; 
    public abstract int VacationTime 
    { 
     get 
     { 
     return VTime; 
     } 
     set 
     { 
     if(value>36) throw new ArgumentException("Exceeded allowed vaction"); 
     if(value<0)throw new ArgumentException("Vacation time must be >0"); 
     vTime= value; 
     } 
    } 


    public void DoSomWork() 
    { 
     //Work 
    } 
} 


public abstract class Manager:IEmployee 
{ 
    public abstract int VacationTime 
    { 
     get 
     { 
     return VTime; 
     } 
     set 
     { 
     if(value>14) throw new ArgumentException("Exceeded allowed vaction"); 
     if(value<0)throw new ArgumentException("Vacation time must be >0"); 
     vTime= value; 
     } 
    } 

    public void DoSomeManaging() 
    { 
     //manage 
    } 

} 

所以我猜我尋找的是一個工作流程這將允許我嵌套單元測試。因此,例如,當我測試Manager類時,我想首先測試它是否通過Employee和IEmployee測試,然後測試特定成員,如DoSomeManaging()

+0

你不清楚你在做什麼。你談論單元測試接口,但這沒有意義。你究竟想要測試什麼?你能提供一個簡短而簡明的對象層次結構例子,並指出你想在這個層次結構中測試什麼? – 2010-09-16 22:11:47

+0

我不想單元測試它自己的接口,但我希望能夠將所有適用於接口的所有測試分組,因此我可以輕鬆地將所有這些測試應用於實現接口的任何類。看看我添加到我的問題的例子。 – 2010-09-16 23:22:39

回答

0

我認爲你想要做的是爲抽象類中的方法創建單元測試。

我不知道它是有道理的要在一個抽象類測試的一個保護方法,但如果你堅持簡單地擴展在專門用於單元測試類的類。通過這種方式,您可以通過擴展類上的公共方法暴露要測試的抽象類上的受保護方法,該方法只需調用抽象類上的方法即可。

如果您有想要unittested抽象類的方法,我建議重構它們放在不同的類,只是將它們公開爲公共方法,並把這些測試。試着從'測試優先'的角度來看待你的繼承樹,我相信你會想出這個解決方案(或類似的)。

0

看起來您已經描述了Visual Studio 2010單元測試不支持的「複合單元測試」。根據這個article,這些事情可以在MbUnit中完成。有可能在Visual Studio 2010中創建abstract tests,這可能不是您想要的。 Here是描述如何在VS中實現抽象測試(繼承示例部分)。

6

我想我知道你的意思。我遇到過同樣的問題。

我的解決方案是創建一個也用於測試的層次結構。我將使用您展示的相同示例。

首先,爲基礎IEmployee提供一個抽象測試類。

它有兩個主要的東西: i。所有你想要的測試方法。二,一種抽象方法,用於返回所需的IEmployee實例。

[TestClass()] 
public abstract class IEmployeeTests 
{ 
    protected abstract GetIEmployeeInstance(); 

    [TestMethod()] 
    public void TestMethod1() 
    { 
    IEmployee target = GetIEmployeeInstance(); 
    // do your IEmployee test here 
    } 

} 

其次,您對IEmployee的每個實現都有一個測試類,實現抽象方法並提供適當的IEmployee實例。

[TestClass()] 
public class WorkerTests : IEmployeeTests 
{ 

    protected override GetIEmployeeInstance() 
    { 
     return new Worker(); 
    } 

} 

[TestClass()] 
public class ManagerTests : IEmployeeTests 
{ 

    protected override GetIEmployeeInstance() 
    { 
     return new Manager(); 
    } 

} 

你可以看到一切正常,並VS讓你在TestView窗口中的每個WorkerTests和ManagerTests類預期的測試方法。 您可以運行它們併爲每個IEmployee接口實現測試結果,只需在基本IEmployeeTests類中創建測試。

您始終可以爲派生的WorkerTests和ManagerTests類添加特定的測試。

現在的問題是,如何實現多個接口的類,比如說僱傭程序員?

public EmployedProgrammer : IEmployee, IProgrammer 
{ 
} 

我們沒有在C#多重繼承,所以這不是一個選項:

[TestClass()] 
public EmployedProgrammerIEmployeeTests : IEmployeeTests, IProgrammerTests 
{ 
    // this doesn't compile as IEmployeeTests, IProgrammerTests are classes, not interfaces 
} 

對於此方案,一個解決方案是讓下面的測試類:

[TestClass()] 
public EmployedProgrammerIEmployeeTests : IEmployeeTests 
{ 
    protected override GetIEmployeeInstance() 
    { 
     return new EmployedProgrammer(); 
    } 
} 

[TestClass()] 
public EmployedProgrammerIProgrammerTests : IProgrammerTests 
{ 
    protected override GetIProgrammerInstance() 
    { 
     return new EmployedProgrammer(); 
    } 
} 

[TestClass()] 
public abstract class IProgrammerTests 
{ 
    protected abstract GetIProgrammerInstance(); 

    [TestMethod()] 
    public void TestMethod1() 
    { 
     IProgrammer target = GetIProgrammerInstance(); 
     // do your IProgrammerTest test here 
    } 

} 

我使用這個結果很好。 希望它有幫助。

問候, 何塞

+1

這被稱爲「合同測試」。以TDD方式工作時,在重構步驟期間,您應該在代碼中抽取Employee類的時候提取抽象測試類。 – 2011-06-25 04:41:19

0

使用更好的測試微軟痣。所以你可以輕鬆地模擬抽象的基類/靜態方法等。請參考以下職位的詳細信息

detouring-abstract-base-classes-using-moles

BenzCar benzCar = new BenzCar();  
new MCar(benzCar) 
    { 
      Drive=() => "Testing" 
    }.InstanceBehavior = MoleBehaviors.Fallthrough; 

var hello = child.Drive(); 

Assert.AreEqual("Benz Car driving. Testing", hello); 
0

運行對多類相同的測試的願望通常意味着你有機會抽取要測試到一個單一類的行爲(無論是它是基礎班或全新的班級,可以組成現有班級)。

考慮您的例子:不是實現在WorkerManager假期的限制,一個新的成員變量添加到Employee,「MaximumVacationDays」,落實在員工類的setter方法的限制,並檢查有限制:

abstract class Employee { 
    private int maximumVacationDays; 
    protected Employee(int maximumVacationDays) { 
     this.maximumVacationDays = maximumVacationDays 
    } 
    public int VacationDays { 
     set { 
      if (value > maximumVacationDays) 
       throw new ArgumentException("Exceeded maximum vacation"); 
      } 
    } 
} 

class Worker: Employee { 
    public Worker(): Employee(14) {} 
} 

class Manager: Employee { 
    public Manager(): Employee(36) {} 
} 

現在,您只有一種方法可以測試,代碼量少。