Ранее я уже приводил пример создания общего шаблона для .NET плагина под любую версию AutoCAD не старше чем 2009-я. Аналогичный шаблон можно создать и для модульных тестов под эти плагины.
В качестве платформы тестирования для управляемых расширений [плагинов] AutoCAD можно использовать Gallio или NUnit.
Gallio благополучно работает с любой версией AutoCAD новее чем 2008 (я не проверял для версий старее чем AutoCAD 2009-й). Однако разработка Gallio на сегодняшний день приостановлена. Тем не менее его можно успешно продолжать использовать. Исходники Gallio опубликованы на GitHub и доступны для изучения\изменения. Однако Gallio работает только с acad.exe - использовать accoreconsole.exe не удастся.
NUnit успешно работает начиная с AutoCAD 2011 и во всех более новых версиях. Версии AutoCAD 2011 - 2014 требуют предварительной установки переменной NEXTFIBERWORLD в значение 0 с последующим перезапуском AutoCAD. По завершению работы тестов, не забудьте переменной NEXTFIBERWORLD снова назначить в качестве значения 1.
Начиная с AutoCAD 2015 компания Autodesk уходит от использования фиберов, поэтому версии AutoCAD, новее чем 2014-я не требуют предварительного изменения обозначенной переменной для успешной работы тестов. Поскольку версии AutoCAD 2010 и все более старые не имеют переменной NEXTFIBERWORLD, то использовать в них тесты NUnit не представляется возможным.
Начиная с AutoCAD 2015 компания Autodesk уходит от использования фиберов, поэтому версии AutoCAD, новее чем 2014-я не требуют предварительного изменения обозначенной переменной для успешной работы тестов. Поскольку версии AutoCAD 2010 и все более старые не имеют переменной NEXTFIBERWORLD, то использовать в них тесты NUnit не представляется возможным.
В отличие от Gallio, NUnit может работать как с acad.exe, так и с accoreconsole.exe.
Т.о. в AutoCAD 2009 и 2010 следует использовать тестовую платформу Gallio, в то время как начиная с AutoCAD 2011 можно использовать либо Gallio, либо NUnit по вашему желанию (я предпочитаю NUnit).
Один и тот же исходный код модульных тестов может компилироваться под разные платформы тестирования. По аналогии с шаблоном плагинов AutoCAD, который я демонстрировал в видео ранее, можно создать шаблон для модульных тестов управляемых расширений AutoCAD. Такой шаблон позволяет пакетно компилировать один и тот же исходный код модульных тестов под разные версии AutoCAD с использованием как платформы Gallio, так и платформы NUnit. В приведённом ниже примере для AutoCAD 2009 и 2010 я генерирую тесты с использованием Gallio, а для AutoCAD 2011-2015 - с использованием NUnit. Оба проекта построены на основе соответствующих шаблонов: первый - на основе шаблона для .NET расширений AutoCAD, а второй - на основе шаблона для создания модульных тестов для .NET расширений AutoCAD.
Дополнительно генерируется набор BAT-файлов, каждый из которых предназначен для запуска тестов в конкретной версии AutoCAD. Результаты тестирования оформляются в виде отчёта в формате HTML. На мой взгляд всё получается достаточно удобно.
Когда-то я писал о баге, присутствующем в AutoCAD .NET API и давал свой вариант обходного решения. Обозначенное ниже видео построено на основе этого кода: тесты выявляют баг в API от Autodesk, а так же проверяют работоспособность моего варианта решения.
UPD:
Добавил генерацию BAT-файла, который последовательно выполняет тесты во всех нужных версиях AutoCAD (в данном случае AutoCAD 2009-2015). Вот видео на эту тему:
Далее привожу код тестов данного видео:
Добавил генерацию BAT-файла, который последовательно выполняет тесты во всех нужных версиях AutoCAD (в данном случае AutoCAD 2009-2015). Вот видео на эту тему:
Далее привожу код тестов данного видео:
/* © Andrey Bushman, 2015 * Tests.cs */ #if !ENTRY_POINT using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Text; using System.Threading; using System.Windows.Controls; using System.Windows.Converters; using System.Windows.Forms; using System.Windows; #if NUNIT using Fw = NUnit.Framework; #elif GALLIO using Gallio.Framework; using Fw = MbUnit.Framework; #endif #if TEIGHA_CLASSIC using Db = Teigha.DatabaseServices; using Rt = Teigha.Runtime; using Gm = Teigha.Geometry; #endif #if NANOCAD using cad = HostMgd.ApplicationServices.Application; using Ap = HostMgd.ApplicationServices; using Ed = HostMgd.EditorInput; #elif BRICSCAD using cad = Bricscad.ApplicationServices.Application; using Ap = Bricscad.ApplicationServices; using Ed = Bricscad.EditorInput; #elif AUTOCAD using cad = Autodesk.AutoCAD.ApplicationServices.Application; using Ap = Autodesk.AutoCAD.ApplicationServices; using Db = Autodesk.AutoCAD.DatabaseServices; using Ed = Autodesk.AutoCAD.EditorInput; using Rt = Autodesk.AutoCAD.Runtime; using Gm = Autodesk.AutoCAD.Geometry; using Br = Autodesk.AutoCAD.BoundaryRepresentation; using Hs = Autodesk.AutoCAD.DatabaseServices.HostApplicationServices; using Us = Autodesk.AutoCAD.DatabaseServices.SymbolUtilityServices; #endif #if AUTOCAD_NEWER_THAN_2012 using corecad = Autodesk.AutoCAD.ApplicationServices.Core.Application; #endif #if AUTOCAD && (PLATFORM_x64 || PLATFORM_x86) using In = Autodesk.AutoCAD.Interop; using Ic = Autodesk.AutoCAD.Interop.Common; #endif using Ex = Bushman.CAD.Extensions.CAD.ExtensionMethods.UnitTests; namespace Bushman.CAD.Extensions.CAD.ExtensionMethods.UnitTests { [Fw.TestFixture, #if NUNIT Fw.Apartment(ApartmentState.STA) #endif ] public class Tests { const String blockName = "TEMP_BLOCK"; // *********************************************************************** [Fw.Test] [Fw.Category("Autodesk API")] public void HasAttributeDefinitions_WhenAttribsExist_IsTrue() { // Create new temp database using (Db.Database db = new Db.Database(true, true)) { using (new WorkingDatabaseSwitcher(db)) { using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { Db.ObjectId id = CreateBlockDefinition(db); Db.BlockTableRecord btr = tr.GetObject(id, Db.OpenMode.ForRead) as Db.BlockTableRecord; Fw.Assert.IsTrue(btr.HasAttributeDefinitions); tr.Commit(); } } } // close and discard changes } // [Fw.Ignore("We can't fix this bug, because it is by Autodesk.")] [Fw.Test] [Fw.Category("Autodesk API")] public void HasAttributeDefinitions_WhenAttribsInNotExist_IsFalse() { Db.ObjectId id = Db.ObjectId.Null; // Create new temp database using (Db.Database db = new Db.Database(true, true)) { using (new WorkingDatabaseSwitcher(db)) { using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { // create new block definition with an attribute definition id = CreateBlockDefinition(db); Db.BlockTableRecord btr = tr.GetObject(id, Db.OpenMode.ForWrite) as Db.BlockTableRecord; // remove all attribute definitions String name = Rt.RXClass.GetClass(typeof(Db.AttributeDefinition)) .Name; foreach (Db.ObjectId itemId in btr) { if (itemId.ObjectClass.Name == name) { Db.DBObject obj = tr.GetObject(itemId, Db.OpenMode.ForWrite); obj.Erase(true); } } tr.Commit(); } } // Check attribute definition count using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { Db.BlockTableRecord btr = tr.GetObject(id, Db.OpenMode.ForWrite) as Db.BlockTableRecord; Fw.Assert.IsFalse(btr.HasAttributeDefinitions); tr.Commit(); } } // close and discard changes } // *********************************************************************** [Fw.Test] [Fw.Category("Bushman API")] public void HasAttDefs_WhenAttribsExist_IsTrue() { // Create new temp database using (Db.Database db = new Db.Database(true, true)) { using (new WorkingDatabaseSwitcher(db)) { using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { Db.ObjectId id = CreateBlockDefinition(db); Db.BlockTableRecord btr = tr.GetObject(id, Db.OpenMode.ForRead) as Db.BlockTableRecord; Fw.Assert.IsTrue(btr.HasAttDefs()); tr.Commit(); } } } // close and discard changes } [Fw.Test] [Fw.Category("Bushman API")] public void HasAttDefs_WhenAttribsIsNotExist_IsFalse() { Db.ObjectId id = Db.ObjectId.Null; // Create new temp database using (Db.Database db = new Db.Database(true, true)) { using (new WorkingDatabaseSwitcher(db)) { using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { id = CreateBlockDefinition(db); Db.BlockTableRecord btr = tr.GetObject(id, Db.OpenMode.ForWrite) as Db.BlockTableRecord; // remove all attribute definitions String name = Rt.RXClass.GetClass(typeof(Db.AttributeDefinition)) .Name; foreach (Db.ObjectId itemId in btr) { if (itemId.ObjectClass.Name == name) { Db.DBObject obj = tr.GetObject(itemId, Db.OpenMode.ForWrite); obj.Erase(true); } } tr.Commit(); } // Check attribute definition count using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { Db.BlockTableRecord btr = tr.GetObject(id, Db.OpenMode.ForWrite) as Db.BlockTableRecord; Fw.Assert.IsFalse(btr.HasAttDefs()); tr.Commit(); } } } // close and discard changes } // ********************************************************************** // Creating of the temp block with an instance of AttributeDefinition internal static Db.ObjectId CreateBlockDefinition(Db.Database db) { if (null == db || db.IsDisposed) { throw new ArgumentException("null == db || db.IsDisposed"); } Db.ObjectId id = Db.ObjectId.Null; // Create a temp block definition with an AttributeDefinition instance using (Db.Transaction tr = db.TransactionManager.StartTransaction()) { Db.BlockTable bt = tr.GetObject(db.BlockTableId, Db.OpenMode.ForWrite ) as Db.BlockTable; Db.BlockTableRecord btr = new Db.BlockTableRecord(); btr.Name = blockName; // its content: the circle and attribite definition Db.Circle circle = new Db.Circle(); circle.SetDatabaseDefaults(); circle.Radius = 20.0; circle.Center = Gm.Point3d.Origin; circle.ColorIndex = 50; btr.AppendEntity(circle); Db.AttributeDefinition atDef = new Db.AttributeDefinition( circle.Center, "Hello!", "ATTRIB", "New value", Us.GetTextStyleStandardId(db)); atDef.SetDatabaseDefaults(); btr.AppendEntity(atDef); id = bt.Add(btr); tr.AddNewlyCreatedDBObject(btr, true); tr.Commit(); } return id; } } } #endif
Комментариев нет:
Отправить комментарий