2013-03-22 103 views
13

比方說,我有兩種搜索算法的實現,它們爲相同的輸入返回相同的結果。他們都實現相同的接口。針對不同實現的相同單元測試

如何使用單個[TestClass]來測試兩個實現,而不是使用最終相同的邏輯創建兩個測試文件?

我可以告訴MSUnit使用不同的構造函數參數兩次啓動其中一個測試嗎?
也許我應該(n)以某種方式注入它?

+0

在你的問題中,你詢問MSTest,但是在你的標籤中你指定了NUnit。你想要哪一個答案? – 2013-03-22 12:42:24

回答

11

使用abstract test class

[TestClass] 
public abstract class SearchTests 
{ 
    private ISearcher _searcherUnderTest; 

    [TestSetup] 
    public void Setup() 
    { 
     _searcherUnderTest = CreateSearcher(); 
    } 

    protected abstract ISearcher CreateSearcher(); 

    [TestMethod] 
    public void Test1(){/*do stuff to _searcherUnderTest*/ } 

    // more tests... 

    [TestClass] 
    public class CoolSearcherTests : SearcherTests 
    { 
     protected override ISearcher CreateSearcher() 
     { 
      return new CoolSearcher(); 
     } 
    } 

    [TestClass] 
    public class LameSearcherTests : SearcherTests 
    { 
     protected override ISearcher CreateSearcher() 
     { 
      return new LameSearcher(); 
     } 
    } 
} 
+1

這是唯一的好方案。 – 2013-04-03 10:20:58

1

我寧願有兩個不同的[TestMethod]在一個[TestClass]每個測試只有一個實現:這種方式失敗的測試將總是正確地指出哪個實現出錯。

+2

而你的兩個[TestMethod]方法可以簡單地作爲一行方法,它們都調用實際包含測試代碼的相同方法。 – Polyfun 2013-03-22 12:02:44

+0

我的搜索實現有〜10種不同的testmethods。你基本上建議將這些方法複製粘貼到同一類中的20個方法(或者在兩個不同的測試類中是10個) – Alex 2013-03-22 12:03:02

+0

@ShellShock,好吧,基本上我現在是如何實現它的,但是我正在尋找一些內置或準備好的功能。 – Alex 2013-03-22 12:03:42

2

你已經用NUnit標記了你的問題,但你問了關於MSTest。你在NUnit中使用參數化測試裝置可以獲得什麼。我不熟悉MSTest在那裏建議一個等效的方法,並且快速搜索表明MSTest可能沒有此功能。

在NUnit中,您可以通過將多個[TestFixture(...)]屬性應用於具有不同參數的夾具類來參數化測試夾具。這些參數將傳遞給燈具構造函數。

由於可傳遞參數的類型有限制,因此您可能需要在指定算法時傳遞一個字符串,然後在構造函數中將提供搜索算法的委託或對象分配給成員字段用於測試。

例如:

using System; 
using System.Collections.Generic; 
using NUnit.Framework; 

namespace MyTests 
{ 
    public static class SearchAlgorithms 
    { 
     public static int DefaultSearch(int target, IList<int> data) 
     { 
      return data.IndexOf(target); 
     } 

     public static int BrokenSearch(int target, IList<int> data) 
     { 
      return 789; 
     } 
    } 

    [TestFixture("forward")] 
    [TestFixture("broken")] 
    public class SearchTests 
    { 
     private Func<int, IList<int>, int> searchMethod; 

     public SearchTests(string algorithmName) 
     { 
      if (algorithmName == "forward") 
      { 
       this.searchMethod = SearchAlgorithms.DefaultSearch; 
       return; 
      } 

      if (algorithmName == "broken") 
      { 
       this.searchMethod = SearchAlgorithms.BrokenSearch; 
      } 
     } 

     [Test] 
     public void SearchFindsCorrectIndex() 
     { 
      Assert.AreEqual(
       1, this.searchMethod(2, new List<int> { 1, 2, 3 })); 
     } 

     [Test] 
     public void SearchReturnsMinusOneWhenTargetNotPresent() 
     { 
      Assert.AreEqual(
       -1, this.searchMethod(4, new List<int> { 1, 2, 3 })); 
     } 
    } 
} 
0

我不能說我用這個方法非常高興,但這裏是我落得這樣做。然後我去尋找更好的方法並找到了這個問題。這種方法符合標準:1)我正在使用MS Test,2)我只寫了一次測試邏輯,3)我可以判斷哪個實現失敗(並且雙擊測試將使我到正確的測試類) 。 該方法使用一個基類來包含所有實際的測試邏輯,然後爲每個實現(我有3個)的派生類設置基礎接口上的特定實現並覆蓋基本測試方法。

[TestClass] 
public abstract class SearchTestBase 
{ 
    protected ISearcher Searcher { get; set; } 

    [TestMethod] 
    public virtual void Find_Results_Correct() 
    { 
     // Arrange (code here) 
     // Act (single line here) 
     var actual = Searcher.Results(input); 
     // Assert 
    } 
} 

(different file...) 
[TestClass] 
public class FastSearcherTest : SearcherTestBase 
{ 
    [TestInitialize] 
    public void TestInitialize() 
    { 
     Searcher = new FastSearcher(); 
    } 

    [TestMethod] 
    public override void Find_Results_Correct() 
    { 
     base.Find_Results_Correct(); 
    } 
} 

(different file...) 
[TestClass] 
public class ThoroughSearcherTest : SearcherTestBase 
{ 
    [TestInitialize] 
    public void TestInitialize() 
    { 
     Searcher = new ThoroughSearcher(); 
    } 

    [TestMethod] 
    public override void Find_Results_Correct() 
    { 
     base.Find_Results_Correct(); 
    } 
} 

所以我不喜歡這種做法是,每次我想添加一個測試,我需要去每個測試文件並覆蓋新的測試方法。我喜歡的是你的3個要求。如果我需要更改測試,我只在一個地方改變邏輯。 我看到這個解決方案優於兩個測試所稱的單個方法的優點是,我不必重複設置正確實現的代碼。在這個解決方案中,你有一行調用base.TestName()的單行,而不是兩行,一行設置Searcher,另一行調用測試。 Visual Studio也使得編寫速度更快......我只需鍵入「覆蓋」並獲取選項列表。自動完成爲我寫剩下的部分。

0

說明基於我的測試。

接受的答案(使用抽象類)只要工作,抽象類和具體類在同一個程序集中。

如果您希望在不同程序集中使用抽象類和具體類,那麼KarlZ提到的方法不幸似乎是必需的。不知道爲什麼會這樣。在這種情況下,TestExplorer將不會顯示TestMethod。

此外,接受的答案使用嵌套在抽象類中的具體類。這似乎不是一個要求。

使用MSTestV2(1.1.17),VS2017進行測試。 以下是使用的示例類。

Assembly 1 
    [TestClass] 
    public abstract class SampleExternal 
    { 
     [TestMethod] 
     public void SampleTest01() 
     { 
      Assert.IsTrue(false, this.GetType().Name); 
     } 
    } 

Assembly 2 
    [TestClass] 
    public abstract class Sample 
    { 
     [TestMethod] 
     public void SampleTest01() 
     { 
      Assert.IsTrue(false, this.GetType().Name); 
     } 

     [TestClass] 
     public class SampleA : Sample 
     { 
     } 
    } 

    [TestClass] 
    public class SampleB : Sample 
    { 
    } 

    [TestClass] 
    public class SampleC : SampleExternal 
    { 
    } 

    [TestClass] 
    public class SampleD : SampleExternal 
    { 
    } 

使用這些時,測試SampleA和SampleB將執行(和設計失敗),但SampleC &採樣不會。

相關問題