我第一次尝试使用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,这意味着你不能捕获测试运行的输出。
是的,我确实知道CC.NET,在使用它之前多年使用它,然后才切换到更现代的CI解决方案 - TeamCity。我在SVN目录中浏览了一会儿,但无法找到我要找的内容。 – Justin
CC.NET运行包含单元测试的构建脚本,并在网页上显示其结果。这不是你想要的吗? –