Меню сайта
Наш опрос
Оцените мой сайт
Всего ответов: 6
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Главная » 2014 » Июль » 22 » Отслеживание событий тестирования NUnit
15:17
Отслеживание событий тестирования NUnit
Работая с фреймворком для unit-тестирования .NET сборок NUnit, Вы не можете получить доступ к событиям тестирования из Ваших фикстур (Fixture) напрямую. Для отслеживания событий Вы должны написать add-in. В этой статье я приведу простой пример того, как это можно сделать.Создадим простую библиотеку классов, которую будем тестировать. using System;namespace TestedLibrary { public class Engine { uint cylinderCount = 1; float capacity = 0.0f; float power = 0.0f; public uint CylinderCount { get { return cylinderCount; } set { if(value < 1) { throw new Exception("Cylinder count must be great then 0"); } cylinderCount = value; } } public float Capacity { get { return capacity; } set { if(value < 0.0) { throw new Exception("Engine capacity must be great then 0.0"); } capacity = value; } } public float Power { get { return power; } set { if(value < 0.0) { throw new Exception("Engine power must be great then 0.0"); } power = value; } } }}namespace TestedLibrary { public class Car { public Car(string name, Engine engine) { Name = name; Engine = engine; } public string Name { get; set; } public Engine Engine { get; set; } }}Создадим проект для тестирования и добавим в него пару фикстур: using NUnit.Framework;using TestedLibrary;namespace Testing { [TestFixture] public class EngineTest { [Test] public void DefaultValues() { Engine engine = new Engine(); Assert.AreEqual(0.0f, engine.Power, 0.1f); Assert.AreEqual(0.0f, engine.Capacity, 0.1f); Assert.AreEqual(1u, engine.CylinderCount); } [Test] public void ManuallySettedValues() { Engine engine = new Engine() { Capacity = 1995.0f, CylinderCount = 4u, Power = 135000.0f }; Assert.AreEqual(135000.0f, engine.Power, 0.1f); Assert.AreEqual(1995.0f, engine.Capacity, 0.1f); Assert.AreEqual(4u, engine.CylinderCount); } }}using NUnit.Framework;using TestedLibrary;namespace Testing { [TestFixture] public class CarTest { [Test] public void Creation() { Engine engine = new Engine() { Capacity = 1995.0f, CylinderCount = 4u, Power = 135000.0f }; Car car = new Car("BMW Х3 xDrive20d Urban", engine); Assert.AreSame(engine, car.Engine); Assert.AreEqual("BMW Х3 xDrive20d Urban", car.Name); } }}Теперь можем скомпилировать и запустить unit-тесты для нашей библиотекиКак я уже говорил, чтобы добраться до событий тестирования, нужно создать add-in для NUnit. Для этого нужно создать новый проект C# из шаблона "Class Library" и добавить в него ссылки на сборки nunit.core.dll и nunit.core.interfaces.dll. По умолчанию они находятся в каталоге C:\Program Files (x86)\NUnit 2.5.10\bin\net-2.0\lib.При запуске NUnit просматривает каталог addins, находящийся рядом с исполняемым файлом, и загружает из всех сборок классы с атрибутом NUnit.Core.Extensibility.NUnitAddinAttribute. Кроме того, эти классы должны реализовывать интерфейс NUnit.Core.Extensibility.IAddin, содержащий всего один метод: namespace NUnit.Core.Extensibility { public interface IAddin { bool Install(IExtensionHost host); }}Для того, чтобы подписаться на прослушивание событий, мы должны реализовать интерфейс NUnit.Core.EventListener и передать объект этого интерфейса в метод Install объекта типа NUnit.Core.Extensibility.IExtensionPoint, который нужно получить следующим образом: IExtensionPoint listeners = host.GetExtensionPoint("EventListeners");Наш класс прослушивания будет называться NUnitReporter и его целью будет создание отчёта в формате HTML. В качестве параметра конструктор этого класса будет принемать имя выходного файл. С учётом всего выше сказанного, полный код класса-расширения будет следующим: using NUnit.Core.Extensibility;namespace NUnitReport { [NUnitAddin] public class Addin : IAddin { public bool Install(IExtensionHost host) { IExtensionPoint listeners = host.GetExtensionPoint("EventListeners"); listeners.Install(new NUnitReporter(@"D:\report.html")); return true; } }}Интерфейс NUnit.Core.EventListener выглядит следующим образом: namespace NUnit.Core { public interface EventListener { void RunFinished(Exception exception); void RunFinished(TestResult result); void RunStarted(string name, int testCount); void SuiteFinished(TestResult result); void SuiteStarted(TestName testName); void TestFinished(TestResult result); void TestOutput(TestOutput testOutput); void TestStarted(TestName testName); void UnhandledException(Exception exception); }}Методы RunStarted и RunFinished вызываются при старте и завершении тестирования. В качестве аргумента методу RunFinished передаются результаты всего тестирования или объект возникшего исключения. SuiteStarted и SuiteFinished вызываются для всех сущностей шире единичного теста: класс, пространство имён, Run. Методы TestStarted и TestFinished будут вызваны при запуске и завершении каждого теста. Наконец, метод UnhendledException вызывается, как ясно из названия, при возникновении необработанного исключения.Приведу простейшую реализацию класса NUnitReporter, собирающего информацию в файл HTML. using System;using System.Collections;using System.IO;using System.Text;using NUnit.Core;namespace NUnitReport { public class NUnitReporter : EventListener { string outFileName; StringBuilder html; public NUnitReporter(string outFileName) { this.outFileName = outFileName; } public void RunFinished(System.Exception exception) { } public void RunFinished(TestResult result) { PrintRunResult(result); using(FileStream stream = File.OpenWrite(outFileName)) { byte[] content = Encoding.UTF8.GetBytes(html.ToString()); stream.Write(content, 0, content.Length); } } void PrintRunResult(TestResult result) { html = new StringBuilder( "<html>\r\n" + "<head>\r\n" + "<meta >\r\n" + "<title>NUnit Report</title>\r\n" + "</head>\r\n" + "<body>\r\n" + "<div >\r\n"); html.AppendLine(String.Format("<h1>{0}</h1>", result.Name)); PrintSuiteResults(result.Results); html.AppendLine( "</div>\r\n" + "</body>\r\n" + "</html>"); } void PrintSuiteResults(IList results) { foreach(TestResult result in results) { html.AppendLine("<div >"); html.AppendLine(String.Format("<h2>{0}</h2>", result.Name)); PrintClassResults(result.Results); html.AppendLine("</div>"); } } void PrintClassResults(IList results) { foreach(TestResult result in results) { html.AppendLine("<div >"); html.AppendLine(String.Format("<h3>{0}</h3>", result.Name)); PrintTestResults(result.Results); html.AppendLine("</div>"); } } void PrintTestResults(IList results) { foreach(TestResult result in results) { string stringResult = ""; if(result.IsSuccess) stringResult = "Success"; else if(result.IsFailure) stringResult = "Failure"; else if(result.IsError) stringResult = "Error"; html.AppendLine("<div >"); html.AppendLine(String.Format("<p>{0}: {1}</p>", result.Name, stringResult)); html.AppendLine("</div>"); } } public void RunStarted(string name, int testCount) { } public void SuiteFinished(TestResult result) { } public void SuiteStarted(TestName testName) { } public void TestFinished(TestResult result) { } public void TestOutput(TestOutput testOutput) { } public void TestStarted(TestName testName) { } public void UnhandledException(System.Exception exception) { } }}Больший интерес во всём примере представляет объект класса NUnit.Core.TestResult. Этот объект содержит информацию о результатах только что завершившегося теста и всех вложенных. К примеру, в результат тестирования пространства имён будут вложены результаты тестирования всех его классов. Эти результаты помещаются в список NUnit.Core.TestResult.Results.Кроме того, класс NUnit.Core.TestResult имеет множетсво интересных свойств: public int AssertCount { get; set; }public string Description { get; }public bool Executed { get; }public FailureSite FailureSite { get; }public virtual string FullName { get; }public bool HasResults { get; }public virtual bool IsError { get; }public virtual bool IsFailure { get; }public virtual bool IsSuccess { get; }public string Message { get; }public virtual string Name { get; }public IList Results { get; }public ResultState ResultState { get; }public virtual string StackTrace { get; set; }public ITest Test { get; }public double Time { get; set; }Файл, содержащий класс Addin следует положить в каталог addins, рядом с исполняемым файлом nunit.exe. Если такого каталога не существует, его нужно создать. Для отладки библиотеки следует аттачиться к процессу nunit-agent.exe (Debug->Attach to Process).Полученный отчёт будет выгладить так:Естественно, что приведённый пример сильно упрощён и не годится для реального использования, но, я надеюсь, демонстрирует общий подход.Исходные тексты проекта можно скачать здесь.
Просмотров: 109 | Добавил: admin | Рейтинг: 0.0/0
Всего комментариев: 0
avatar
Форма входа
Календарь
«  Июль 2014  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей