如果我有接口IFoo,並且有幾個類實現它,那麼根據接口測試所有這些類的最好/最優雅/最聰明的方法是什麼?NUnit - 如何測試實現特定接口的所有類
我想減少測試代碼的重複,但仍然'保持對'單元測試的原則。
您認爲最佳做法是什麼?我使用NUnit,但我想任何單元測試框架中的示例都是有效的
如果我有接口IFoo,並且有幾個類實現它,那麼根據接口測試所有這些類的最好/最優雅/最聰明的方法是什麼?NUnit - 如何測試實現特定接口的所有類
我想減少測試代碼的重複,但仍然'保持對'單元測試的原則。
您認爲最佳做法是什麼?我使用NUnit,但我想任何單元測試框架中的示例都是有效的
如果你有類實現任何一個接口,那麼他們都需要實現該接口中的方法。爲了測試這些類,你需要爲每個類創建一個單元測試類。
讓我們改用更智能的路線;如果您的目標是避免代碼和測試代碼重複您可能想創建一個抽象類,而不是處理重複代碼。
E.g.您有以下接口:
public interface IFoo {
public void CommonCode();
public void SpecificCode();
}
您可能要創建一個抽象類:
public abstract class AbstractFoo : IFoo {
public void CommonCode() {
SpecificCode();
}
public abstract void SpecificCode();
}
測試,很容易;實現抽象類的測試類無論是作爲一個內部類:
[TextFixture]
public void TestClass {
private class TestFoo : AbstractFoo {
boolean hasCalledSpecificCode = false;
public void SpecificCode() {
hasCalledSpecificCode = true;
}
}
[Test]
public void testCommonCallsSpecificCode() {
TestFoo fooFighter = new TestFoo();
fooFighter.CommonCode();
Assert.That(fooFighter.hasCalledSpecificCode, Is.True());
}
}
...還是讓測試類擴展抽象類本身是否適合你的想象。
[TestFixture]
public void TestClass : AbstractFoo {
boolean hasCalledSpecificCode;
public void specificCode() {
hasCalledSpecificCode = true;
}
[Test]
public void testCommonCallsSpecificCode() {
AbstractFoo fooFighter = this;
hasCalledSpecificCode = false;
fooFighter.CommonCode();
Assert.That(fooFighter.hasCalledSpecificCode, Is.True());
}
}
擁有抽象類來處理接口隱含的通用代碼會給出更簡潔的代碼設計。
我希望這對你有意義。
作爲一個方面說明,這就是所謂的Template Method pattern常見的設計模式。在上面的例子中,模板方法是CommonCode
方法,而SpecificCode
被稱爲存根或掛鉤。這個想法是任何人都可以擴展行爲,而不需要知道幕後的東西。
很多框架依賴於這種行爲模式,例如, ASP.NET您必須在頁面或用戶控件中實現掛鉤,例如由Load
事件調用的生成的Page_Load
方法,模板方法會在幕後調用掛鉤。這裏有更多的例子。基本上,你必須實現的任何使用「load」,「init」或「render」這些詞語的模板方法都會被調用。
我不使用NUnit,但我測試了C++接口。我會首先測試一個TestFoo類,它是它的一個基本實現,以確保通用的東西有效。那麼你只需要測試每個接口獨有的東西。
我不認爲這是最佳實踐。
簡單的事實是,一個接口只不過是一個方法實現的契約。這是一個而不是合同)a)該方法應該如何實現,b)該方法應該做什麼(它只能保證返回類型),我收集的兩個原因將是你想要的動機這種測試。
如果你真的想在你的方法實現的控制,你的選擇:
實施例:
public static ReturnType MethodName (this IMyinterface myImplementation, SomeObject someParameter)
{
//method body goes here
}
任何實施適當引用該擴展方法將精確地發射該擴展方法,所以你只需要測試一次。
我Jon Limjap不同意時,他說,
這不是在任一個。)該方法如何應實施和b。)什麼方法應該做的正是(它只保證合同返回類型),我收集的兩個原因是你想要這種測試的動機。
在返回類型中可能有很多未指定的合同部分。語言無關的例子:上鍊表,ArrayList中,CircularlyLinkedList
public interface List {
// adds o and returns the list
public List add(Object o);
// removed the first occurrence of o and returns the list
public List remove(Object o);
}
你的單元測試,和所有其它的應該不僅測試該列表自身的返回,而且他們已經適當修改。
關於按合同設計有earlier question,這可以幫助您指導干預這些測試的正確方向。
如果你不想合同的開銷,我建議試驗檯,沿着線什麼建議Spoike:
abstract class BaseListTest {
abstract public List newListInstance();
public void testAddToList() {
// do some adding tests
}
public void testRemoveFromList() {
// do some removing tests
}
}
class ArrayListTest < BaseListTest {
List newListInstance() { new ArrayList(); }
public void arrayListSpecificTest1() {
// test something about ArrayLists beyond the List requirements
}
}
當測試一個接口或基類的合同,我寧願讓測試框架自動地關心查找所有的實現者。這使您可以專注於測試的接口,併合理確信所有實現都將進行測試,而無需執行大量手動實現。
CombinatorialTest
和UsingImplementations
屬性。除了測試界面的基礎知識之外,還應測試每個單獨的實現是否遵循其特定要求。
@Emperor XLII
我喜歡在MbUnit的組合測試的聲音,我試着NUnit的抽象基類,接口測試技術,雖然它的工作,你需要有一個單獨的測試一個類實現的每個接口的夾具(因爲在C#中沒有多重繼承 - 儘管可以使用內部類,這非常酷)。 實際上這很好,甚至可能是有利的,因爲它通過接口將實現類的測試分組。但是如果框架更聰明,那將會很好。如果我可以使用一個屬性來將一個類標記爲接口的「官方」測試類,並且該框架將搜索測試的程序集中所有實現該接口的類,然後在其上運行這些測試。
這會很酷。
[TestFixture]類的層次結構如何?將常用測試代碼放在基本測試類中,並將其繼承到子測試類中。
@Spoike:+1,但是一個小問題是您的代碼不是C#。 – user7116 2008-10-06 17:48:35