2012-01-27 53 views
5

我想在運行之前報告它們,並且可以選擇通過shell腳本運行單個測試,而無需管理類別。我們有一些非託管代碼會使進程處於不良狀態,並且有時很高興能夠按照每個nunit控制檯運行單獨運行每個測試。nunit-console可以列出測試夾具中的所有測試名稱嗎?

+0

'NUnit控制檯MyAssembly.dll程序/ labels'將顯示所有的測試,因爲他們跑,但我是正確的思維,你想要的是獲取預先列出,然後提示用戶(或將它們添加到'/ runlist ='文件中)? 不想使用類別的理由是什麼? – ClickRick 2014-04-08 00:29:49

+0

我們希望他們提前,正確。這裏的關鍵是我們希望一次運行一個,即每次運行一次,一次又一次地運行nunit-console。我們改變了組件,以至於我們不再需要這樣做,但是我仍然很驚訝,沒有看到這方面的答案。 – 2014-04-10 04:14:50

+0

如果這仍然是你的問題,我會試着用他們的EventListener類來看看(參見http://imistaken.blogspot.co.uk/2009/03/nunit-extensions-adding-logic-at-run .html作爲例子),看看你是否可以通過這種方式獲得列表,但是這要依靠能夠抑制當時測試的實際運行,而這是我不經過嘗試就不知道的。 – ClickRick 2014-04-10 12:41:24

回答

0

nunit-console仍然不支持此選項。然而,使用反射來獲取測試用例列表是非常簡單的。在非常基礎的層面上,您需要列出所有public classpublic方法以及相應的[Test]/[TestFixture]屬性。根據測試的結構,您可能需要執行額外的過濾,例如刪除標記爲[Ignore]屬性的任何測試,或考慮基本類中的測試方法。

在基本層面,代碼會是這個樣子:

// Load the assembly containing your fixtures 
Assembly a = Assembly.LoadFrom(assemblyName); 

// Foreach public class that is a TestFixture and not Ignored 
foreach (var c in a.GetTypes() 
        .Where(x=>x.IsPublic 
        && (x.GetCustomAttributes(typeof(NUnit.Framework.TestFixtureAttribute)).Count() > 0) 
        && (x.GetCustomAttributes(typeof(NUnit.Framework.IgnoreAttribute)).Count() ==0))) 
{ 
    // For each public method that is a Test and not Ignored 
    foreach (var m in c.GetMethods() 
         .Where(x=>x.IsPublic 
         && (x.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute)).Count() > 0) 
         && (x.GetCustomAttributes(typeof(NUnit.Framework.IgnoreAttribute)).Count() ==0))) 
    { 
     // Print out the test name 
     Console.WriteLine("{0}.{1}", c.ToString(), m.Name); 
     // Alternately, print out the command line to run test case using nunit-console 
     //Console.WriteLine("nunit-console /run:{0}.{1} {2}", c.ToString(), m.Name, assemblyName); 
    } 
} 

顯然你可以簡化這個有點,如果你只是想從一個特定的TestFixture的測試方法。

正如評論中所說,如果您需要關注其他NUnit屬性,例如TestCaseTestCaseSource,這會變得更加複雜。我修改了下面的代碼來支持這些屬性的一些功能。

static void PrintTestNames(string assemblyName) { 
    Assembly assembly = Assembly.LoadFrom(assemblyName); 

    foreach (var fixture in assembly.GetTypes().Where(x => x.IsPublic 
             && (x.GetCustomAttributes(typeof(TestFixtureAttribute)).Count() > 0) 
             && (x.GetCustomAttributes(typeof(IgnoreAttribute)).Count() == 0))) { 
     foreach(var method in fixture.GetMethods().Where(x=>x.IsPublic 
      && (x.GetCustomAttributes(typeof(IgnoreAttribute)).Count() == 0) 
      && ((x.GetCustomAttributes(typeof(TestAttribute)).Count() > 0) 
       || (x.GetCustomAttributes(typeof(TestCaseAttribute)).Count() > 0) 
       || (x.GetCustomAttributes(typeof(TestCaseSourceAttribute)).Count() > 0)) 
      )) { 
      var testAttributes = method.GetCustomAttributes(typeof(TestAttribute)) as IEnumerable<TestAttribute>; 
      var caseAttributes = method.GetCustomAttributes(typeof(TestCaseAttribute)) as IEnumerable<TestCaseAttribute>; 
      var caseSourceAttributes = method.GetCustomAttributes(typeof(TestCaseSourceAttribute)) as IEnumerable<TestCaseSourceAttribute>; 

      if (caseAttributes.Count() > 0) { 
       foreach(var testCase in caseAttributes) { 
        if (!string.IsNullOrEmpty(testCase.TestName)) { 
         PrintTestName(fixture.ToString(), testCase.TestName); 
        } 
        else { 
         string arguments = ExtractArguments(testCase.Arguments); 
         PrintTestName(fixture.ToString(), method.Name + arguments); 
        } 
       } 
      } 
      else if (caseSourceAttributes.Count() > 0) { 
       foreach (var testCase in caseSourceAttributes) { 
        var sourceName = testCase.SourceName; 
        if (!string.IsNullOrEmpty(sourceName)) { 
         var staticMember = fixture.GetField(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); 
         var instanceMember = fixture.GetField(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 
         var staticMethodMember = fixture.GetMethod(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); 
         var instanceMethodMember = fixture.GetMethod(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 
         var staticPropMember = fixture.GetProperty(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); 
         var instancePropMember = fixture.GetProperty(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 


         IEnumerable memberValues; 

         if (null != staticMember) { 
          memberValues = staticMember.GetValue(null) as IEnumerable; 
         } 
         else if (null != instanceMember) { 
          var instance = Activator.CreateInstance(fixture); 
          memberValues = instanceMember.GetValue(instance) as IEnumerable; 
         } else if(null != staticMethodMember) { 
          memberValues = staticMethodMember.Invoke(null,new object [0]) as IEnumerable; 
         } 
         else if (null != instanceMethodMember) { 
          var instance = Activator.CreateInstance(fixture); 
          memberValues = instanceMethodMember.Invoke(instance, new object[0]) as IEnumerable; 
         } 
         else if (null != staticPropMember) { 
          memberValues = staticPropMember.GetValue(null) as IEnumerable; 
         } 
         else if (null != instancePropMember) { 
          var instance = Activator.CreateInstance(fixture); 
          memberValues = instancePropMember.GetValue(instance) as IEnumerable; 
         } 
         else { 
          Console.WriteLine("*** Ooops...Looks like I don't know how to get {0} for fixture {1}", sourceName, fixture.ToString()); 
          continue; 
         } 

         foreach (var memberValue in memberValues) { 
          if (null != memberValue as IEnumerable) { 
           PrintTestName(fixture.ToString(), method.Name + ExtractArguments(memberValue as IEnumerable)); 
          } 
          else { 
           PrintTestName(fixture.ToString(), method.Name + "(" + memberValue.ToString() + ")"); 
          } 
         } 
        } else { 
         Console.WriteLine("*** Ooops...Looks like I don't know how to handle test {0} for fixture {1}", method.Name, fixture.ToString()); 
        } 
       } 
      } 
      else { 
       PrintTestName(fixture.ToString(), method.Name); 
      } 
     } 
    } 
} 

static string ExtractArguments(IEnumerable arguments) { 
    string caseArgs = "("; 
    bool first = true; 
    foreach (var arg in arguments) { 
     if (first) first = false; 
     else caseArgs += ","; 
     caseArgs += Convert.ToString(arg); 
    } 
    return caseArgs + ")"; 
} 

static void PrintTestName(string fixture, string testName) { 
    Console.WriteLine("{0}.{1}", fixture, testName); 
    //Console.WriteLine("nunit-console /run:{0}.{1} {2}", fixture, testName, assemblyName); 
} 

如果你通過上面的代碼,你可能會注意到,我已經處理功能,其中TestCaseSource的測試是一個字符串,命名的屬性/方法/場。您還會注意到雖然代碼還有更多代碼,但它仍然非常簡單易用,所以如果您使用的是TestCaseSource的替代版本,或者您還有其他NUnit屬性,則可以輕鬆擴展它沒有照顧。

爲上面添加一個計數器也是很容易的,這樣您就可以獲得相當數量的測試結果,並且與nunit控制檯運行的測試數量相當。

+0

這將獲得基礎知識,但如果您使用某些可以自動從不同輸入生成測試的更高級屬性,那麼您的運氣不好! – 2015-06-02 14:28:56

+0

@SebastianGood我已經添加了對TestCase +一些TestCaseSource排列的支持。擴展代碼以處理其他TestCaseSource選項(或其他屬性,我還沒有找到)應該是直截了當,如果您使用替代的,但我會留下*閱讀*的練習。 – forsvarir 2015-06-03 06:35:45

+0

您還需要考慮測試類從具有這些屬性的(抽象)基類繼承的情況。然後需要調整計數多次運行相同的測試方法, – WebDancer 2017-03-24 10:39:38

相關問題