2011-08-19 81 views
1

我有一个ASP.NET MVC Web应用程序,用于监视我公司系统的状态 - Windows服务,wcf服务,Web应用程序等...我有一个C#NUnit测试项目具有检查系统内不同事物的测试用例。目前我使用TestDriven.Net在Visual Studio中运行测试用例,或者我可以使用nunit gui运行测试用例。在ASP.NET MVC应用程序中调用nunit测试用例

我想要做的是将测试项目DLL导入到我的ASP.NET MVC Web应用程序中,并以某种方式调用它来运行项目中的所有测试用例,并输出每个测试的测试用例名称,持续时间和结果案件到一个网页。这可能吗?如果是这样,我该怎么去做,或者是否有一些预制框架可以提供这种能力?我知道像teamCity这样的CI框架可以运行测试用例并输出到网页上,但是我正在寻找它在我自己的Web应用程序中,并且对我来说,对输出的设计有一定程度的控制。

回答

4

我第一次尝试使用Process.Start启动nunit控制台进程并将其输出重定向到我的web应用程序,但这不是一个好的解决方案,因为Process类的重定向输出被缓冲,并且您无法控制何时它冲刷缓冲区。我发现像msbuild这样的程序工作得很好,并且不断刷新,但是使用nunit-console它会保留在输出中,直到所有测试用例都完成为止,这意味着在测试用例运行时无法看到测试用例的进度。

的解决方案是使用RemoteTestRunner NUnit的类和创建实现NUnit.Core.EventListener接口的事件监听器类:

public class NUnitEventListener : NUnit.Core.EventListener 
    { 
     public event EventHandler CompletedRun; 
     public StringBuilder Output; 
     private int TotalTestsPassed = 0; 
     private int TotalTestsErrored = 0; 

     public void RunStarted(string name, int testCount) 
     { 
      Output.AppendLine(TimeStamp + "Running " + testCount + " tests in " + name + "<br/><br/>"); 
      TotalTestsPassed = 0; 
      TotalTestsErrored = 0; 
     } 

     public void RunFinished(System.Exception exception) 
     { 
      Output.AppendLine(TimeStamp + "Run errored: " + exception.ToString() + "<br/>"); 
      //notify event consumers. 
      if (CompletedRun != null) 
       CompletedRun(exception, new EventArgs()); 
     } 

     public void RunFinished(TestResult result) 
     { 
      Output.AppendLine(TimeStamp + "<label class='normal " + (TotalTestsErrored == 0 ? "green" : "red") 
       + "'>" + TotalTestsPassed + " tests passed, " + TotalTestsErrored + " tests failed</label><br/>"); 
      Output.AppendLine(TimeStamp + "Run completed in " + result.Time + " seconds<br/>"); 
      //notify event consumers. 
      if (CompletedRun != null) 
       CompletedRun(result, new EventArgs()); 
     } 

     public void TestStarted(TestName testName) 
     { 
      Output.AppendLine(TimeStamp + testName.FullName + "<br/>"); 
     } 

     public void TestOutput(TestOutput testOutput) 
     { 
      if(testOutput.Text.IndexOf("NHibernate:") == -1) 
       Output.AppendLine(TimeStamp + testOutput.Text + "<br/>"); 
     } 

     public void TestFinished(TestResult result) 
     { 
      if (result.IsSuccess) 
      { 
       Output.AppendLine(TimeStamp + "<label class='green normal'>Test Passed!</label><br/><br/>"); 
       TotalTestsPassed++; 
      } 
      else 
      { 
       Output.AppendLine(TimeStamp + "<label class='red normal'>Test Failed!<br/>" + result.Message.Replace(Environment.NewLine, "<br/>") + "</label><br/>"); 
       TotalTestsErrored++; 
      } 
     } 

     public void UnhandledException(System.Exception exception) 
     { 
      Output.AppendLine(TimeStamp + "Unhandled Exception: " + exception.ToString() + "<br/>"); 
     } 

     public void SuiteStarted(TestName testName) 
     { 
     } 

     public void SuiteFinished(TestResult result) 
     { 
     } 

     private string TimeStamp 
     { 
      get 
      { 
       return "[" + DateTime.Now.ToString() + "] "; 
      } 
     } 
    } 

之后,创建调用RemoteTestRunner和使用您的性感的TestRunner类新的事件监听器类:

public static class TestRunner 
    { 
     public static bool InProgress = false; 
     public static StringBuilder Output = new StringBuilder(); 
     private static RemoteTestRunner Runner; 

     public static void Start(string fileName) 
     { 
      InProgress = true; 
      Output = new StringBuilder(); 
      StartTests(fileName); 
     } 

     private static void StartTests(string fileName) 
     { 
      //start nunit. 
      var testPackage = new TestPackage(fileName); 
      Runner = new RemoteTestRunner(); 
      Runner.Load(testPackage); 
      var nunitEventListener = new NUnitEventListener(); 
      nunitEventListener.CompletedRun += new EventHandler(nunitEventListener_CompletedRun); 
      nunitEventListener.Output = Output; 
      Runner.BeginRun(nunitEventListener); 
     } 

     static void nunitEventListener_CompletedRun(object sender, EventArgs e) 
     { 
      if (Runner != null) 
      { 
       Runner.CancelRun(); 
       Runner = null; 
      } 
      InProgress = false; 
     } 
    } 

现在调用的TestRunner类在ASP.NET MVC控制器:

public class TestController : ApplicationController 
    { 
     //GET: /Test/Index/ 
     public ActionResult Index() 
     { 
      TestRunner.Start(@"C:\PathToTestProject\bin\Release\SystemTest.dll"); 
      return View(); 
     } 

     //POST: /Test/GetOutput/ 
     [AcceptVerbs(HttpVerbs.Post)] 
     public ActionResult GetOutput() 
     { 
      var result = new 
      { 
       InProgress = TestRunner.InProgress, 
       Output = TestRunner.Output.ToString() 
      }; 
      return Json(result); 
     } 
    } 

最后,创建一个简单的视图,将输出显示为测试用例运行。矿用道场,但它可以很容易地修改与jQuery或香草JavaScript来的工作:

<script type="test/javascript"> 
var nunit = { 

    init: function() { 

     nunit.get(); 

    }, 

    get: function() { 

     //ajax call. 
     ajax.post("test/getoutput/", {}, nunit.display); 

    }, 

    display: function (result) { 

     console.debug(result); 
     dojo.byId("output").innerHTML = result.Output.length > 0 ? result.Output : dojo.byId("output").innerHTML; 
     if (result.InProgress) 
      window.setTimeout(nunit.get, 10000); 

    } 

}; 

dojo.addOnLoad(nunit.init); 
</script> 

<div id="output"> 
    The tests are running, please wait.... 
</div> 

就是这样......希望这可以帮助一些人,因为所有的在线的例子RemoteTestRunner的(包括计算器)传递一个NullListener,这意味着你不能捕获测试运行的输出。

1

我不知道你是否知道CruiseControl.NET是一个CI的开源项目。如果没有,请检查其Web应用程序的构建报告管理器http://sourceforge.net/projects/ccnet/,你将能够看到他们是如何实现你想要做的。

+0

是的,我确实知道CC.NET,在使用它之前多年使用它,然后才切换到更现代的CI解决方案 - TeamCity。我在SVN目录中浏览了一会儿,但无法找到我要找的内容。 – Justin

+0

CC.NET运行包含单元测试的构建脚本,并在网页上显示其结果。这不是你想要的吗? –