Author Topic: Unit Testing in AutoCAD  (Read 15402 times)

0 Members and 1 Guest are viewing this topic.

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2139
  • class keyThumper<T>:ILazy<T>
Unit Testing in AutoCAD
« on: August 20, 2011, 12:21:09 AM »

Has anyone done any work incorporating Unit Testing (Test First Development) with AutoCAD apps ??

If so, care to share opinions ?

Regards
kdub


Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

kaefer

  • Guest
Re: Unit Testing in AutoCAD
« Reply #1 on: August 20, 2011, 02:13:18 AM »
Gallio Release Note 3.0.5

Quote
AutoCAD Integration

Mike Sandberg has added support for testing AutoCAD plugins.

It turns out that AutoCAD has a managed extensibility model so you can create your own plugins using .Net and the ObjectARX toolkit.  Unfortunately it is somewhat difficult to write unit tests for plugins becuase they must run within the main UI thread of AutoCAD.

The AutoCAD integration for Gallio works by loading a shim into the AutoCAD application from which it can launch tests.  To enable this integration, specify the "AutoCAD" runner type to the Echo, Icarus, MSBuild, NAnt or PowerShell runners.

For example:

    Gallio.Echo.exe MyTestAssembly.dll /r:AutoCAD [other options...]

AutoCAD integration is not yet available from within the IDE.  We will be working to improve this use case in the future.

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2139
  • class keyThumper<T>:ILazy<T>
Re: Unit Testing in AutoCAD
« Reply #2 on: August 20, 2011, 03:48:22 AM »

Thanks kaefer ..

 seems that I have a heap more study to do :)


regards,
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

kaefer

  • Guest
Re: Unit Testing in AutoCAD
« Reply #3 on: August 20, 2011, 05:14:14 AM »
I was just about able to deploy stand-alone tests by referencing Gallio.dll and MbUnit.dll and using the Icarus test runner. Barring a certain amount of study I have no idea how to implement the technique described above, let alone devising meaningful tests against the AutoCAD drawing Database.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #4 on: June 07, 2012, 07:26:37 AM »
2 kaefer

Can you show an source code of your unit test example (for AutoCAD)?

Regards

kaefer

  • Guest
Re: Unit Testing in AutoCAD
« Reply #5 on: June 07, 2012, 07:29:09 AM »
Can you show an source code of your unit test example (for AutoCAD)?

Sorry, can't. I've still no idea. Anyone?

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #6 on: June 07, 2012, 07:32:50 AM »
I am able to use NUnit and MSTest a little, but Gallio to me isn't clear. Whether correctly I understood your question: are you want, that I gave an example, when it can be necessary in AutoCAD?
« Last Edit: June 07, 2012, 12:34:43 PM by Andrey »

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #7 on: June 10, 2014, 08:15:41 AM »
I use NUnit in the Resharper Test runner in Visual Studio 2012. If you try to use an AutoCAD-dependent object in the test it crashes the test (but not the runner) with  System.InvalidProgramException : Common Language Runtime detected an invalid program but you can test classes that have AutoCAD objects as properties by calling a constructor that sets the AutoCAD-based property to null. I evolved this using properties which were actually a class that contained AutoCAD objects (RXClass) properties so this can work down down down into layers.

I use a constructor with a boolean flag for unit tests. The other constructor(s) call that flagged constructor before they run. This means that the constructor you are usually looking for to use in anger is as you expect. The unit testing constructor shows up in Intellisense so that is why I have the boolean parameter an obvious name. I

You can test test some AutoCAD elements, namely UI elements that are handled by the SDK DLLs. I used a Palette tab in a test that checked some UI elements against a settings class and it works fine. "handled", did I say? Yes, that's how the SDK DLLs work with the Visual Studio designer and they seem to work in the tests too.

To use the SDK DLLs in the Unit Tests you need to reference them in the test project (duh!) and also set Copy Local to True (wut!). Yes, the tests need to be in their own project but you already do that, right?

In my example below you may notice I use internal classes. The class you're testing doesn't necessarily need to be public ... BUT if you want to test internal classes then you need to add `[assembly:InternalsVisibleTo("CADFindReplaceTests")]` in your app's AssemblyInfo.cs. Google InternalsVisibleTo and also be aware of the security implications of shipping assemblies that have a back-door like the one this creates.

Here's a highly-contrived example of what I am on about ...

Code - C#: [Select]
  1. using NUnit.Framework;
  2. using Lots.Of.Google;
  3.  
  4.  
  5. [Test()]
  6. [STAThread]
  7. public void Test_Breaks()
  8. {
  9.   ThingWithAutocadBits thing = new ThingWithAutocadBits(unitTesting); // Bang !
  10.         Assert.Fail("FAIL");  // You won't get this far
  11. }
  12.  
  13.  
  14. [Test()]
  15. [STAThread]
  16. public void Test_Runs_But_My_Code_Sucks()
  17. {
  18.   ThingWithAutocadBits thing = new ThingWithAutocadBits(unitTesting: true);
  19.         Assert.Pass("#FAIL");  // aw, damn! There is no justice.
  20. }



Code - C#: [Select]
  1. internal class ThingWithAutocadBits
  2. {
  3.         internal string ThingName { get; set; }
  4.         internal bool TellMeItsNotTrue { get; set; }
  5.         internal AutoCADObjectOfSomeSorts iBreakThings { get; set; }
  6.  
  7.  /// <summary>
  8.  /// This Ctor is for Unit Testing - it avoids the dependency on AutoCAD objcts of doom
  9.  /// It is always called by the default Ctor.
  10.  /// </summary>
  11.  /// <param name="UnitTesting">Value here doesn't matter, just its presence.</param>
  12.         internal SearchOptions(bool UnitTesting = true)
  13.         {
  14.         ThingName = "Nigel";
  15.         TellMeItsNotTrue = true;
  16.         iBreakThings = null;
  17.         }
  18.  
  19.  
  20.         internal ThingWithAutocadBits() : this (true)
  21.         {
  22.         iBreakThings = Whatever.You.Like.Eh;
  23.         }
  24. }

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #8 on: June 11, 2014, 09:06:42 AM »
I use the Gallio. It works fine.

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #9 on: February 16, 2015, 10:49:02 PM »
I've just discovered https://bitbucket.org/IsaacRodriguez/civilizeddevelopment/src/ - this approach looks interesting. It should be relatively easy (compared to solving the wars over politics and religion) to adapt this to run tests in Visual Studio Test Runners for any framework, or just use the frame work here. There seems to be some quite good ideas in here. Can't type ... reading.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #10 on: February 17, 2015, 01:58:40 AM »
this approach looks interesting.
...  to adapt this to run tests in Visual Studio Test Runners for any framework, or just use the frame work here.
What exactly? Can MSVS use the Gallio platform also? Did you try it?

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #11 on: February 18, 2015, 07:07:42 PM »
What exactly?
Good Question. Thank you, you made me think about it a lot more because I didn't have an instant "good answer".

You could use the Test runner in that app to run a set of tests inside AutoCAD that needed AutoCAD objects. These test would be a different set of test than you would run in something like NUnit against your code that has no external dependencies. The more I think about this the more I think it is a bad idea, mostly because it is too different from the normal, accepted way of doing things.

Can MSVS use the Gallio platform also? Did you try it?
Older versions of ReSharper had a test runners for Gallio. That's not a big deal, really, I don't mind using other Test Runners. NUnit's test runner can run a batch of tests so I can build all the different versions of an app and then run all the tests at once in NUnit. Gallio's Test runners look good, from what I have seen.

I looked at Gallio's source code but I have not tried it yet. My concern is that development has stopped on it. I could update it myself as it is on Github at https://github.com/Gallio/mbunit-v3/commits/master but that looks like it would be a lot of work in the future. Gallio is very big and complex and could easily turn out being more work to maintain than my projects I am supposed to be working on. Test frameworks like NUnit and XUnit are still very active and popular. Popular frameworks have a lot more support, code samples, documentation (Gallio's documentation is gone, only on the Web Archive).


I am currently considering using http://nsubstitute.github.io/ to use fake AutoCAD objects. NSubstitute builds fake objects from Interfaces, It is possible to build Interfaces for AutoCAD managed objects by decompiling AutoCAD's managed wrapper DLLs (I used Dotpeek) then use ReSharper to extract an Interface from the classes you want to fake (Resharper also extracts Interface members from the class's dependencies so you get a lot of members). It would probably be easier to just make the Interfaces yourself if they were simple.

I know that testing code with external dependencies is considered bad by unit-testing purists but I would also like to test the expected behaviour of those objects. Creating something like a fake DBText would allow me to set its properties and then test that my code is using those properties as I expect. Using fakes would also allow me to ignore any other behaviour I am not interested in testing...and probably save me from a lot of acad.exe crashes.

For those of you who got nervous when I mentioned decompiling AutoCAD DLLs, there is a precedent for this: http://adndevblog.typepad.com/autocad/2012/08/a-rich-source-of-autocad-net-sample-code.html and also at http://through-the-interface.typepad.com/through_the_interface/2010/02/debugging-into-autocads-net-api-layer-using-reflector-part-1.html - I'm not reverse-engineering AutoCAD, merely deconstructing it to test things. Well, that's my story.

@Andrey - I tried to keep my language clear here because I know your first language is not English, please let me know if anything is not clear to you. I would like to hear your thoughts on this.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Unit Testing in AutoCAD
« Reply #12 on: February 19, 2015, 02:27:23 PM »
I just can't see testing any code that relies on AutoCAD to ever be a reality.

It would think it would take so much time and effort to build fakes to behave like they would in AutoCAD environment and then with changes to maintain you would never have time to actually use it.
....
Number of fakes required to build, mass number of system variables whose settings will change the behavior of objects, some objects require a certain order for assigning properties, so many different contexts, etc....
 

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #13 on: February 19, 2015, 02:46:28 PM »
@Jeff H,

It is necessary to separate independent and integration testing. I did it for my some application. It requires many forces and time, but it gives me big confidence about the quality of my software.

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #14 on: February 19, 2015, 03:48:33 PM »
I know nobody who is interested the AutoCAD extensions testing (except me). :)
The more I think about this the more I think it is a bad idea, mostly because it is too different from the normal, accepted way of doing things.
It is necessary to separate independent and integration testing as I told in my previous message. It is usual common practice. I've learned this through this book. This is good book.

Older versions of ReSharper had a test runners for Gallio. That's not a big deal, really, I don't mind using other Test Runners. NUnit's test runner can run a batch of tests so I can build all the different versions of an app and then run all the tests at once in NUnit.
I prefer to use NUnit and Gallio.

I looked at Gallio's source code but I have not tried it yet.
I read its sources too and I have some expirience of Gallio using for AutoCAD testing.

My concern is that development has stopped on it.
It is not a problem for me because the sources are exist and I know how to extend it for newer AutoCAD versions (I did it already as a practice and it work fine). Current capabilities of Gallio are fine for me.

I am currently considering using http://nsubstitute.github.io/ to use fake AutoCAD objects. NSubstitute builds fake objects from Interfaces, It is possible to build Interfaces for AutoCAD managed objects by decompiling AutoCAD's managed wrapper DLLs (I used Dotpeek) then use ReSharper to extract an Interface from the classes you want to fake (Resharper also extracts Interface members from the class's dependencies so you get a lot of members).
I know what is it and how it works (the book has the materials about this). I use it too in my tests.

I know that testing code with external dependencies is considered bad by unit-testing purists but I would also like to test the expected behaviour of those objects.
Such tests are inevitable and usefull too.

For those of you who got nervous when I mentioned decompiling AutoCAD DLLs, there is a precedent for this
I have this official description, so I know what is .Net Reflector. :)

@Andrey - I tried to keep my language clear here because I know your first language is not English, please let me know if anything is not clear to you. I would like to hear your thoughts on this.
Thank you. I understood you. I am not a professional in the writting of the tests for AutoCAD extensions, but if this theme is interesting for you, then we can discovery it together later. For me is interesting to write the extensions for NUnit for capabilities of testing AutoCAD, nanoCAD, BricsCAD and any Teigha-based application.

Now I spend my time for learning of Haskell and WebGL. I didn't write a code for AutoCAD long ago.

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #15 on: February 22, 2015, 06:03:41 PM »
It would think it would take so much time and effort to build fakes to behave like they would in AutoCAD environment and then with changes to maintain you would never have time to actually use it.
....
Number of fakes required to build, mass number of system variables whose settings will change the behavior of objects, some objects require a certain order for assigning properties, so many different contexts, etc....
I am rapidly coming to the same conclusion. Andrey has already worked this out - the only way to test the behaviour of an AutoCAD object is to run the tests in AutoCAD and the way that works for him is to use Gallio.

As an aside, I tried Microsoft Fakes but that had a  lot of trouble building Fakes. When I eventually got it to build one it only worked on a few things. Chained method calls just didn't work, they didn't call the fakes after they got one layer deep. ObjectId is a struct so faking that is problematic. Properties are relatively easy to fake but chained properties involve behaviour which is not easy to fake. Also amusing was the seven-hundred-thousand line C-sharp file that Microsoft Fakes created.

The managed libraries are only managed wrappers and therefore only part of the AutoCAD object story anyway so faking those just won't work. Even if you manage to fake these you're faking a fake, especially if you fake the SDK DLLs which actually are fakes but dumb ones. That ain't gunna work. It didn't work.

It is necessary to separate independent and integration testing. I did it for my some application. It requires many forces and time, but it gives me big confidence about the quality of my software.
(the bold is my emphasis) Yeah, me too. I recently refactored the core of my app - this improved performance around 5x but it also broke some of my tests because I removed a lot of abstraction and disconnections to the AutoCAD objects I am manipulating. I want my tests back (now!) but I also like the way it runs now. I can see ways to test it but actually doing it is the hard part - I really need the AutoCAD objects because their behaviour and properties are an important part of the process.

The Repo I linked to above is interesting because it has a test runner that runs inside AutoCAD. Here is the explanation I should have added in my original post (sorry) http://civilizeddevelopment.typepad.com/civilized-development/2011/03/tinyrunner-implementing-a-civil-3d-extension.html. Here's a Google search (TypePad's search is pants) for more that Isaac has written more about the Colibra library: https://www.google.com.au/search?q=colibra+site%3Ahttp%3A%2F%2Fcivilizeddevelopment.typepad.com This is the enxt rabbit hole I plan on diving down.

Thinking out loud here ...

Not all tests need to run in AutoCAD, just the ones that concern themselves with the properties and behaviour of AutoCAD objects. These are more integration tests than unit tests but they should still be automated and easy to create and use. My goal is to find a lightweight solution that runs tests in AutoCAD. The solution must be light-weight, flexible and future-proof. It should Just WorkTM.

Creating and managing AutoCAD objects need not be difficult, you should be able to use something like Nunit SetUp and TearDown. Well, that's the theory.

Lightweight
This has two considerations: doing and maintaining. I am not concerned that setting up the initial infrastructure would be a big job if it was easy to use and maintain.
Gallio is lightweight to run but not to maintain. Well, so is AutoCAD really but I digress. What I really want to be able to do is to set the Solution Configuration in Visual Studio and then run the tests in a test runner. It should just work. Unit tests need to be easy and fast or you just won't bother.

I also want to be able to build all the versions and run all the tests at once. With non-AutoCAD unit tests this is relatively simple, batch-build in Visual Studio the run all the tests in the NUnit test runner GUI - it works quite well. I wouldn't even care if the tests to some time to run if it was trivial to run them - a batch file that opens each CAD application, runs the tests and records the results would work for me. This could run on a Virtual Machine with a bunch of CAD applications on it. When it is finished you can reset the VM for the next lot of tests. This sounds do-able to me with a batch file and scripts to run the test runner in each application. Setting it up would be a fair bit of work but once the template was built then repeating the effort would/should be trivial.

Flexible
For me is interesting to write the extensions for NUnit for capabilities of testing AutoCAD, nanoCAD, BricsCAD and any Teigha-based application.
Me too and I want this to work automatically. I want a process that is easy to repeat, something I can create a project template for and just add it to a Visual Studio solution, write some tests and press go.

future-proof
My main concern with Gallio is that it must be maintained and it is HUGE, so that maintenance could be a big effort.

It's kind of liberating to be stumbling around in the dark, in the broad daylight of the Internet. Care to join me? What are your thoughts?

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: Unit Testing in AutoCAD
« Reply #16 on: February 23, 2015, 03:42:21 PM »
Me too and I want this to work automatically. I want a process that is easy to repeat, something I can create a project template for and just add it to a Visual Studio solution, write some tests and press go.
I prefer to use the NUnit instead of the Visual Studio test runner. This case my tests haven't depending of any IDE.

future-proof
My main concern with Gallio is that it must be maintained and it is HUGE, so that maintenance could be a big effort.

Care to join me? What are your thoughts?
Do you mean about writting of NUnit extensions for testing of any CAD?
If "yes" then it is interesting for me. We can discuss it in the Skype or email, for example (I have some ideas about of architecture its implementation).

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: Unit Testing in AutoCAD
« Reply #17 on: February 23, 2015, 04:38:18 PM »
I remember starting to make my own test runner for Bricscad for integration testing, it wouldn't be hard to hand build your own testing suite.
The thing with projects like Gallio is they have to cater for 'all' types of applications and include a lot of things you don't need or use, by hand coding your own you can build only what you need as you need it.

This maybe a start or food for thought: http://www.theswamp.org/index.php?topic=47549.msg525741#msg525741

I'd also suggest moving to a more functional style of programming, this (mostly) removes the need for mocks and interfaces, by creating class methods that only take simple data types and not 'objects' that hold the data as 'state' they are a lot easier and safer to test and more reusable.

Anyway, for all my CAD/.net dev I'm off to F# :)
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #18 on: February 23, 2015, 06:24:55 PM »
I had a play with TinyTest (links are in my previous posts) and I've managed to get it to build and run its own tests inside AutoCAD. It's very simple but that isn't such a bad thing. It does support Setup and Teardown methods which is handy.

A Visual Studio 2013 solution is attached. You will need to replace the project references in the TinyTest project with whatever AutoCAD references you use. Don't forget "Copy Local". You may need to change the .NET framework too (I set it to .NET 4). I changed (ie. probably broke) a few things in it, particularly the Class and method Attributes - I changed those to match NUnit.

Build it, then netload "TinyTest.dll". Run the command RunFrameworkTests and it will (I hope) run its own tests.

I've only just started playing with this but I think it looks promising. I'd like it to have more of NUnit's assertions and a GUI runner and/or more verbose output. A GUI runner is not such a difficult thing to do (famous last words) and probably an interesting WPF exercise.

As an aside, I actually did get the NUnit 2.6.4 GUI runner to run inside AutoCAD but it doesn't play well with the AcMgd etc. DLLs. It also crashes AutoCAD if you try to add it a second time. It was a mess. I didn't look too closely at NUnitLite but I think that has more potential and would be more manageable than the full version of NUnit. I would still use NUnit for my main testing, only deferring to this TinyTest for stuff I couldn't break away from AutoCAD. Yeah, it's a crutch. Meh.

I'd also suggest moving to a more functional style of programming, this (mostly) removes the need for mocks and interfaces, by creating class methods that only take simple data types and not 'objects' that hold the data as 'state' they are a lot easier and safer to test and more reusable.
I agree with that in sentiment but in practise I find it just leads to more layers of indirection, I get a lot of classes talking about other classes and less JFDI. The other thing I don't like about Fakes is that it removes AutoCAD's behaviour and as well all know, that can be a bastard-thing that needs to be monitored. Using Fakes also tests your assumptions, am I actually asking *CAD to do what I think I'm asking it to do?

I prefer to use the NUnit instead of the Visual Studio test runner. This case my tests haven't depending of any IDE.
I don't really mind which test runner I use as long as it works and I get results. I like NUnit's runner because I can run a lot of tests all at once. I like Resharpers runner because it is right in front of me, I can run my tests with a two mouse-clicks (or Ctrl-U, Ctrl-R).

Care to join me? What are your thoughts?
Do you mean about writing of NUnit extensions for testing of any CAD?
If "yes" then it is interesting for me. We can discuss it in the Skype or email, for example (I have some ideas about of architecture its implementation).
Nunit is just as huge as MBUnit / Gallio, NUnit Version 3 even more so. I think MickD is on to something here...
I remember starting to make my own test runner for Bricscad for integration testing, it wouldn't be hard to hand build your own testing suite.
The thing with projects like Gallio is they have to cater for 'all' types of applications and include a lot of things you don't need or use, by hand coding your own you can build only what you need as you need it.

If I develop anything useful I want to make sure that everybody can use it. This The Swamp and other communities have given me tremendous value and help and I really want to be able to give this back. I am happy to discuss things offline but anything I build is for everybody. Here are my license terms from the attached project...

Code - C#: [Select]
  1. /*CAD bloke's License terms are simple:  Knock yourself out, whatever, wherever, whenever, however, whyever but if it kills anything it is entirely your fault because you touched it last and you should do backups and source control. If you claim this as your own and extort funds for it then Karma will get you while you are sleeping. If you use it in anger and it works then attribution would be rather nice (and for Isaac too), if it doesn't work then you never heard of CAD bloke and it definitely wasn't Isaac's fault.*/
Isaac Rodriguez is the original writer of TinyText. Thanks Isaac.

Note, I haven't changed much of it as yet, the file headers are a pre-emptive strike so nobody blames Isaac or Autodesk if I broke it.

...edit - added another version of the Visual Studio solution I have fiddled with. I also left the original attached in case I broke it.
« Last Edit: February 23, 2015, 10:02:48 PM by CADbloke »

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #19 on: March 01, 2015, 08:16:34 PM »
What I have discovered so far ...
  • It works. You can run tests that create objects inside transactions and then use these objects in your test.
  • You can't mix NUnit tests with tests based on TinyTest. This is because in the NUnit project you will probably need to add the AutoCAD DLL references and set the copy local to true (this doesn't mean you can use AutoCAD objects in NUnit tests, only that the NUnit assembly will actually load). In the TinyTest Assembly you set the copy local to false, as per normal because it runs inside AutoCAD.
  • Running the tests by launching AutoCAD from a .BAT file with a .SCR script to NETLOAD the test DLL and then run the command that fires the tests is much faster than running the tests via Visual Studio's debug.
  • You can run the tests in the debugger and it works very well. I included the TinyTest source code by recursively linking it into the Test project so I could debug it (and fix it) but the debugger should step through it anyway if you have built it yourself with PDB etc. symbols and referenced it as a DLL.
  • Don't forget to lock the Document if you are messing with the DataBase.
  • It's still very much a work in progress. I don't know how much progress I will make in any particular time-frame, presently I am just focussed on getting it running tests so I can run tests, not so I can write the next NUnit. I would like to write a GUI runner for it but I make no promises about the eventuality of that.
...Still going...

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #20 on: March 03, 2015, 11:07:05 PM »
So, I abandoned TinyTest. Attached is a Visual Studio 2013 Project / Solution that will...
run Nunit 3.0 tests in the NUnitLite console runner inside AutoCAD.
see  attached screengrab for what I am talking about

You will need to edit
  • The AutoCAD DLL References
  • the paths in the the .bat file that runs the tests
  • The debug settings in the project settings in Visual Studio
  • the path in the .SCR script fie
  • whatever I have forgotten that is hardcoded. It shouldn't be much more.

The Project references are mostly on Nuget, the packages should download the first time you build it.

Yes, NUunit 3 is an Alpha version, I couldn't get NUnitLite 2.x to run. I did get the full version of the NUnit 3.0 Console running too but there seems no point, Lite is easier to set up and use.

If your test project has any AutoCAD references the you can't run it in a test runner outside AutoCAD, ie. not in Visual Studio.

More later, I have literally been left holding the baby

*** If you are using AutoCAD 2013 then you may have problems with Application.DocumentManager.MdiActiveDocument being null. Yes, I checked fiberworld. This change fixed it and the tests passed...

Code - C#: [Select]
  1. // Remove
  2. Document doc = Application.DocumentManager.MdiActiveDocument;
  3. Database db = doc.Database;
  4. // Replace with
  5. Database db = HostApplicationServices.WorkingDatabase;
  6. Document doc = Application.DocumentManager.GetDocument(db);

It ain't pretty but it worked on my machine. Read Owen's reply below the post I linked for why it ain't pretty.
« Last Edit: March 04, 2015, 07:24:17 PM by CADbloke »

Mike Leslie

  • Guest
Re: Unit Testing in AutoCAD
« Reply #21 on: March 04, 2015, 09:36:00 AM »
I have been using the Test Explorer in Visual Studio for testing AutoCAD .NET dlls out of process.

What I mean is that I have three projects:

1)  .NET in-process dll inside AutoCAD
2)  .NET out-of-process dll
3)  .NET test project

The tests can run with either one or two instances of Visual Studio running.

For one instance of VS (when the in-process one is working well), it is the out-of process project and test project that are open.  My tests call my out-of-process functions which then get a reference to AutoCAD, NETLOAD the in-process dll, and either execute a command or (my new favorite) use AcadApplication.GetInterfaceObject to execute a function and return a COM object.  If a COM exception occurs or the returned object failed an assert, the test fails.

If the in-process one needs debugged, then I have two instances of Visual Studio running.  I build and run the in-process one (which starts AutoCAD with my debugger running

   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
    <StartProgram>C:\Program Files\Autodesk\AutoCAD 2013\acad.exe</StartProgram>
    <StartAction>Program</StartAction>
  </PropertyGroup>
), I then can run the tests from the other Visual Studio project, but I will get to use the breakpoints and see the variable values from the in-process debugger.


It is a little cumbersome with the two projects, but it has been working well for me since for my work, I usually prefer to drive AutoCAD from the outside as opposed to making new widgets for use in the AutoCAD UI.  It is WAY faster to run a .NET in-process module to do the "real work" than to write the same process using the AutoCAD COM library.  You get access to features that the COM library doesn't support and you can do it with reliable database transactions and less likelihood of "RPC server is telling you to buzz off cuz it's busy." errors.

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #22 on: March 04, 2015, 04:21:50 PM »
Mike,that sounds effective but, as you said, cumbersome.

You can add the NUnitLite Console runner to an existing NUnit project...
1. In Nuget, add NUnitLite 3 and the NUnit 3 Framework.
2. Get the App.cs file from the zip I posted, it has the code to display the console
3. Copy the Command class and tweak it as you wish, it launches NUnitLite and runs the tests. You can set all sorts of options there.
4. You can set the startup to run a .SCR file to netload the DLL and run the command.

That's about all there is to it, the rest is semantics.

I use a .BAT file to launch AutoCAD to make running the tests a 1-right-click-run operation from Visual Studio's solution explorer, or F5 to debug the tests. Try the Visual studio solution I attached above, it is a very simple example of how I made it work.

EDIT: Duh moment: the .BAT file is totally unnecessary - Ctrl-F5 (Start without Debugging) will run the current build configuration with the debug settings you have so you still need the .SCR file and you need to set the Test project as the startup project.
« Last Edit: March 10, 2015, 12:00:46 AM by CADbloke »

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #23 on: March 04, 2015, 05:46:35 PM »
For those of you following along, here is the relevant C# code

App.cs
Code - C#: [Select]
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Autodesk.AutoCAD.Runtime;
  4.  
  5. [assembly: ExtensionApplication(typeof (NUnitAutoCADTestRunner.NUnitRunnerApp))]
  6.  
  7. namespace NUnitAutoCADTestRunner
  8. {
  9.   /// <summary> AutoCAD extension application implementation. </summary>
  10.   /// <seealso cref="T:Autodesk.AutoCAD.Runtime.IExtensionApplication"/>
  11.   public class NUnitRunnerApp : IExtensionApplication
  12.   {
  13.     public void Initialize() { AllocConsole(); }
  14.     public void Terminate() { FreeConsole(); }
  15.  
  16. // http://stackoverflow.com/questions/3917202/how-do-i-include-a-console-in-winforms/3917353#3917353
  17. // http://web.archive.org/web/20100815055904/http://www.thereforesystems.com/output-to-console-in-windows-forms-application
  18. // http://www.codeproject.com/Questions/229000/Will-Console-writeline-work-in-Windows-Application
  19.  
  20.     /// <summary> Allocates a new console for current process. </summary>
  21.     [DllImport("kernel32.dll")]
  22.     public static extern Boolean AllocConsole();
  23.  
  24.  
  25.     /// <summary> Frees the console. </summary>
  26.     [DllImport("kernel32.dll")]
  27.     public static extern Boolean FreeConsole();
  28.   }
  29. }

Command.cs
Code - C#: [Select]
  1. using Autodesk.AutoCAD.Runtime;
  2. using System.Collections.Generic;
  3. using NUnitAutoCADTestRunner;
  4. using NUnitLite.Runner;
  5.  
  6. [assembly: CommandClass(typeof (TestRunner))]
  7. namespace NUnitAutoCADTestRunner
  8. {
  9.   public class TestRunner
  10.   {
  11.      /// <summary> This command runs the NUnit tests in this assembly. </summary>
  12.     [CommandMethod("RunNUnitTests")]
  13.     public void RunNUnitTests()
  14.      {
  15.        string[] NunitArgs = new List<string>
  16.        {
  17.          // for details of options see  http://www.nunit.com/index.php?p=nunitliteOptions&r=3.0
  18.          "--verbose"  
  19.        }.ToArray();
  20.        
  21.        new NUnitLite.Runner.TextUI().Execute(NunitArgs);
  22.      }
  23.   }
  24. }

...update - you'll want to decorate your NUnit Test classes with the Single-Threaded Apartment State attribute (new to NUnnit 3, NUnit 2 uses [RequiresSTA])
Code - C#: [Select]
  1. [TestFixture, Apartment(ApartmentState.STA)]
  2. public class No_cause_for_alarm_This_is_just_a_Test
  3. { ...
...I had trouble with AutoCAD 2015 in debug. Probably something about not getting enough FIBER.
« Last Edit: March 10, 2015, 12:01:27 AM by CADbloke »

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #24 on: March 08, 2015, 07:25:59 AM »
http://www.pluralsight.com/courses/outside-in-tdd is a very interesting look into different types of automated code testing, in particular Unit Testing, Acceptance Testing and testing the behaviour of your code. There are quite a few other courses there on Unit testing and many other topics so it you lay out the $$ for a 1-month subscription you could get plenty of value from that site.

Note that I still have plenty more tests in the unit test project than I have in the test project that runs inside AutoCAD which are very much integration and behaviour tests, they don't replace unit tests, they add to the confidence-building test collection.

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Unit Testing in AutoCAD
« Reply #25 on: March 10, 2015, 10:50:36 PM »
I posted my latest version of CADtest to Github. There's a VB version as well. I started a thread at  http://www.theswamp.org/index.php?topic=49035 for any comments you may have.