在 ASP.NET MVC 应用程序中调用 nunit 测试用例

发布于 2024-11-30 06:32:32 字数 415 浏览 1 评论 0原文

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

我想要做的是将测试项目 dll 导入到我的 ASP.NET MVC Web 应用程序中,并以某种方式调用它来运行项目中的所有测试用例,并将每个测试用例的测试用例名称、持续时间和结果输出到 Web页。这可能吗?如果是这样,我将如何去做,或者是否有一些预先构建的框架可以提供这种能力?我知道像 teamCity 这样的 CI 框架可以运行测试用例并输出到网页,但我希望它位于我自己的 Web 应用程序中,以便我对输出的设计方式有一定程度的控制。

I have an ASP.NET MVC web app used to monitor the state of my company's system - windows services, wcf services, web apps, etc... I have a C# NUnit test project that has test cases that check different things within the system. Currently I use TestDriven.Net to run the test cases within Visual Studio, or I can run the test cases using the nunit gui.

What I would like to do is import the test project dll into my ASP.NET MVC web app and somehow invoke it to run all test cases within the project and output the test case name, duration, and result of each test case to a web page. Is this possible? If so, how would I go about doing it or is there some pre-built framework that gives this ability? I know that CI frameworks like teamCity can run the test cases and output to a webpage, but I'm looking for it to be within my own web app and for me to have some level of control over how the output is designed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一腔孤↑勇 2024-12-07 06:32:32

我首先尝试使用 Process.Start 启动 nunit-console 进程并将其输出重定向到我的 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);
        }
    }

最后,创建一个简单的视图来显示测试用例运行时的输出。我的使用 dojo,但可以轻松修改它以使用 jquery 或 vanilla 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 的所有在线示例(包括 stackoverflow 上)都传递 NullListener,这意味着您可以不捕获测试运行的输出。

I first tried starting the nunit-console process using Process.Start and redirecting its output to my web app, however this is not a good solution because the redirected output from the Process class is buffered and you have no control over when it flushes the buffer. I found certain programs like msbuild work great and it flushes constantly, however with nunit-console it holds onto the output until all test cases are complete, which means you can't see the progress of the test cases as they run.

The solution is to use the RemoteTestRunner nunit class and create an event listener class that implements the NUnit.Core.EventListener interface:

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() + "] ";
            }
        }
    }

After that, create a TestRunner class that calls RemoteTestRunner and uses your sexy new event listener class:

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;
        }
    }

Now call the TestRunner class in your ASP.NET MVC Controller:

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);
        }
    }

Lastly, create a simple view to show the output as the test cases run. Mine uses dojo but it can easily be modified to work with jquery or vanilla 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>

That's it... Hope this helps some others, as all of the examples online of RemoteTestRunner (including on stackoverflow) pass in a NullListener, which means you can't capture the output of the test run.

楠木可依 2024-12-07 06:32:32

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

I wonder if you know about CruiseControl.NET that is a open source project for CI. If not, Check its web app for build report manager http://sourceforge.net/projects/ccnet/ you will be able to see how they achieved what you want to do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文