shupsta2010 发表于 2021-10-8 12:40:05

在AutoCAD中运行自动化测试得到eLockViolation

**** Hidden Message *****

n.yuan 发表于 2021-10-10 10:38:43

我猜你的测试方法测试的是你在自定义命令中使用的CAD DLL方法(CommandMethod[]),而不是CommandMethod本身。当AutoCAD。NET API代码修改绘图数据库中的任何东西,数据库的文件必须被锁定。当从CommandMethod执行代码时,CommandMethod在文档上下文中执行时会自动锁定文档(除非CommandMethod有其CommandFlags。会话标志设置,例如代码在应用程序上下文中执行)。
所以,对于你的每一个测试方法,如果CAD。要测试的. NET代码是要对当前绘图的数据库进行修改,你需要先锁定文件。类似于:

void testsomethemodincaddll()
{
var DWG As Application。document manager . MdiActiveDocument;
使用(dwg。LockDocument())
{
//您的测试代码在这里
}
}
当然,如果CAD。NET代码不会更改打开的图形中的任何内容,因此无需锁定它。

CADbloke 发表于 2021-10-11 06:39:34

如果没有任何代码查看,很难判断出哪里出了问题。我没有在整个过程中使用CAD测试,但iirc它在AutoCAD过程中通过命令运行控制台和nunit。如果诺曼的回答不起作用,请发布一些代码或链接到回购协议,以便我们查看。

shupsta2010 发表于 2021-10-11 11:14:48

感谢您的回复。我将尝试在此处解释代码。

      public void SetUp()
      {
            zones = new ShimZones(new List());
            IZone zone = new Zone("1", "306406", "H");
            zones.addZone(zone);
            
      }
ShimZones是一个从普通Zones类继承的对象,它只是重写了一个序列化方法,这是我第一次遇到这个问题。这就是我的工作。
Zones 对象几乎只是一个包含 Zone 对象列表的类,具有一些用于操作该列表的帮助器方法。
[代码 1]
这是为要添加的区域项而调用的构造函数。
在我的非测试代码中,在将新区域添加到Zones对象后,我运行此方法
public void UpdateColor()
      {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
            using (DocumentLock doclock = doc.LockDocument())
            using (Transaction tr = tm.StartTransaction())
            {
                ObjectId newObjectId = this.GetObjectId();
                Polyline btr = (Polyline)tr.GetObject(newObjectId, OpenMode.ForWrite);
                btr.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, (short)color);
                tr.Commit();
            }
      }
但是这似乎是发生崩溃和错误的地方。但是当我运行这个测试方法

      
      public void zone_renumber_to_2()
      {
            zones.RenumberZone(0, "2", "H");
            Assert.IsTrue(zones.zoneList.zoneNum == "2");
            Assert.IsTrue(zones.zoneList.color == 116);
      }
public void RenumberZone(int index, string newNum, string newThermo)
      {
            zoneList.zoneNum = newNum;
            zoneList.thermostat = newThermo.ToUpper();
            zoneList.color = Zone.getZoneColor(this, newNum);
            zoneList.UpdateColor();
            SerializeZones();
      }
时,UpdateColor()方法运行没有问题,并且表示Zone的pline的颜色发生了变化?
非常奇怪的行为,一种方法能够毫无问题地运行 UpdateColor() 方法,而另一种方法则无法运行。

shupsta2010 发表于 2021-10-11 16:10:50


我刚才确实尝试过,将我共享的设置方法包装在using语句中并锁定文档,但结果是一样的。此外,进行颜色更新的方法已经有一个锁定文档的using语句。

n.yuan 发表于 2021-10-12 10:25:01

这确实有点奇怪
在我看来,唯一有点可疑的是在UpdateColor方法中:要更改的实体由“this.GetObjectId()”标识,这反过来又会追溯到区域对象的句柄。当在测试中调用UpdateColor()时,句柄是否可能属于另一个打开的图形,而不是当前的MdiActiveDocument
我不喜欢在每个CAD操作方法中获取MdiActiveDocument并锁定文档,如果类已经有了识别其依赖关系数据库的方法。在您的情况下,方法是这样的。GetObjectId()已经暗示Zone类本身知道句柄属于哪个数据库。因此,为什么需要获取MdiActiveDocument才能访问数据库,然后访问TransactionManager?您可以这样做:
var newObjectId=this。GetObjectId()
使用(var-tran=newObjectId.Database.TransactionManager.StartTransaction())
{

}
这样,您可以将文档锁完全保留在UpdateColor方法之外,并让调用进程决定是否需要锁。例如,在文档上下文中,不需要锁定,而在应用程序上下文(如此处的测试)中,需要在测试调用中显式锁定文档
此外,我们都知道,如果测试涉及AutoCAD过程,则测试实际上会从“单元测试”变为“集成测试”。并且这是困难和耗时的。因此,在很多情况下,我从来都不喜欢这样做,因为这样做不值得花时间。但对于你的区域类。如果需要“单元测试”(我知道,有些老板/公司要求),我会坚持“单元测试”,而不是“集成测试”,也就是说,我会考虑通过为Zone类的单元测试提供一个mocking/empty UpdateColor()方法来取代AutoCAD:毕竟,Zone类单元测试是为了确保在调用RenumberZone()时,应该按照预期发生一些事情,因此,只要调用mocking UpdateColor,单元测试就应该通过。

shupsta2010 发表于 2021-10-12 15:52:45

谢谢你的帮助n.yuan,这是非常有价值的。
我按照您的描述对 UpdateColor 进行了更改
public void UpdateColor()
      {
            ObjectId newObjectId = this.GetObjectId();
            
            using (Transaction tr = newObjectId.Database.TransactionManager.StartTransaction())
            {
               
                Polyline btr = (Polyline)tr.GetObject(newObjectId, OpenMode.ForWrite);
                btr.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, (short)color);
                tr.Commit();
            }
      }
并对 GetObjectId 进行了一些更改,现在它看起来像这样
public ObjectId GetObjectId()
      {
            Document doc = Active.Document;
            ObjectId newObjectId = new ObjectId();
            
            using (doc.Database.TransactionManager.StartTransaction())
            {
                long l = Int64.Parse(handle, System.Globalization.NumberStyles.AllowHexSpecifier);
                Handle h = new Handle(l);
                newObjectId = Active.Database.GetObjectId(false, h, 0);
            }
            return newObjectId;
      }
现在在测试的 Setup 函数中,如果我锁定文档

      public void SetUp()
      {
            using (Active.Document.LockDocument())
            {
                zones = new ShimZones(new List());
                IZone zone = new Zone("1", "306406", "H");
                zones.addZone(zone);
            }
               
      }
则不会崩溃
,但是在以后的测试中,即使我锁定了文档,也会发生相同的崩溃?

      
      public void zone_renumber_to_2()
      {
            using (Active.Document.LockDocument())
            {
                zones.RenumberZone(0, "2", "H");
                Assert.IsTrue(zones.zoneList.zoneNum == "2");
                Assert.IsTrue(zones.zoneList.color == 116);
            }
            
      }
我应该如何存储该句柄的句柄和数据库信息?我正在继承此代码并尝试改进它,同时学习如何为AutoCAD插件编写代码。
再次感谢!

n.yuan 发表于 2021-10-13 09:05:20

在GetObjectId()方法中引发异常?哪条线
需要注意的一点是:无需使用该方法启动事务

shupsta2010 发表于 2021-10-13 10:31:32

谢谢n元!移除GetObjectId()中的那个事务就修复了它!我想我认为创建一个新的ObjectId对象将保证一个事务。

n.yuan 发表于 2021-10-14 08:50:03

很高兴听到由于我的“不太确定”提示,问题得到了解决。这仍然是一个令人惊讶和困惑的问题:为什么一个无用的事务,或者一个在DocumentLock范围内打开的事务仍然会引发eLockViolation,而另一个事务在它没有引起异常后立即打开?真奇怪!
页: [1]
查看完整版本: 在AutoCAD中运行自动化测试得到eLockViolation