Вызов тестовых примеров nunit в приложении ASP.NET MVC - PullRequest
1 голос
/ 19 августа 2011

У меня есть веб-приложение ASP.NET MVC, используемое для мониторинга состояния системы моей компании - службы Windows, службы wcf, веб-приложения и т. Д. У меня есть тестовый проект C # NUnit, в котором есть контрольные примеры, которые проверяют разные вещи в системе. В настоящее время я использую TestDriven.Net для запуска тестовых случаев в Visual Studio или могу запускать тестовые примеры с помощью графического интерфейса nunit.

То, что я хотел бы сделать, это импортировать dll тестового проекта в мое веб-приложение ASP.NET MVC и каким-то образом вызвать его для запуска всех тестовых случаев в проекте и вывода имени тестового примера, продолжительности и результата каждого тестового случая. на веб-страницу. Это возможно? Если так, как бы я поступил, или есть какая-то заранее созданная структура, которая дает эту возможность? Я знаю, что CI-фреймворки, такие как teamCity, могут запускать тестовые примеры и выводить их на веб-страницу, но я ищу, чтобы они были в моем собственном веб-приложении и чтобы я мог иметь некоторый уровень контроля над тем, как устроен вывод. *

Ответы [ 2 ]

4 голосов
/ 25 августа 2011

Сначала я попытался запустить процесс nunit-console с помощью Process.Start и перенаправить его вывод в мое веб-приложение, однако это не очень хорошее решение, поскольку перенаправленный вывод из класса Process буферизуется, и вы не можете контролировать его очищает буфер Я обнаружил, что некоторые программы, такие как msbuild, отлично работают и постоянно сбрасываются, однако с помощью nunit-console он удерживает вывод до тех пор, пока все тестовые примеры не будут завершены, что означает, что вы не можете видеть ход выполнения тестовых примеров при их запуске.

Решением является использование класса nunit RemoteTestRunner и создание класса прослушивателя событий, который реализует интерфейс 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() + "] ";
            }
        }
    }

После этого создайте класс TestRunner, который вызывает RemoteTestRunner и использует ваш новый класс прослушивателя событий:

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 или 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, что означает, что вы не можете захватить выходные данные тестового прогона.

1 голос
/ 20 августа 2011

Интересно, знаете ли вы о CruiseControl.NET, который является проектом с открытым исходным кодом для CI. Если нет, проверьте его веб-приложение для менеджера отчетов о сборке http://sourceforge.net/projects/ccnet/, вы сможете увидеть, как они достигли того, что вы хотите сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...