I'm considering rewriting an AutoCAD plugin built with the .NET/C# API. The current version has no unit or integration tests. Since many of the important AutoCAD objects only exist inside the AutoCAD runtime, testing them directly would require integration tests and a little extra setup.
To make unit testing possible, I started separating the domain and business logic from the AutoCAD-specific code. For example, a Zone is represented by an AutoCAD Polyline, but I could expose the relevant behavior through abstractions such as an IZoneDataProvider for storing business data and an IZoneGeometry for checking whether points fall inside the zone. In tests, these could use in-memory implementations, while the production code would use adapters around AutoCAD objects.
This approach works reasonably well for some behavior, but I'm questioning whether it remains useful as more rules are added. For example, when a Polyline becomes a Zone, its color and the colors of related objects may need to change based on the ZoneId. Adding that behavior to the domain model would require another abstraction, such as an IZoneColorEntity with a CurrentColor property. The AutoCAD adapter would then implement several interfaces that closely resemble the AutoCAD API.
At that point, it feels like I'm merely wrapping the external API rather than creating genuinely independent domain logic. If most of the business rules are about reading and modifying AutoCAD objects, would it be better to skip the separate domain project and focus on integration or functional tests using real AutoCAD scenarios? Or is the additional abstraction still worthwhile for maintainability and testing?
2 Answers
Unit tests aren’t automatically better than integration tests, and they shouldn’t be the goal by themselves. Choose the test boundary based on where defects are likely to occur. For pure business rules, use simple unit tests with plain data. For geometry, object lifetimes, transactions, and AutoCAD-specific behavior, use integration tests against the real environment.
You can also use a thinner architecture: keep AutoCAD adapters at the edge, put genuinely independent policies in ordinary C# classes, and let application services coordinate the two. You don’t need an interface for every AutoCAD property, and you don’t need to force the entire model into a fakeable domain object. A small number of focused abstractions plus realistic end-to-end scenarios will usually provide better value than a large mock-heavy design.
Don’t create abstractions just to make every line unit-testable. If the behavior is inherently about AutoCAD objects, an integration test using the real runtime is often the most valuable test because it verifies the actual API contract. Mocks and interfaces can drift away from the real AutoCAD behavior and give you false confidence.
A separate domain layer is worthwhile when it contains substantial, deterministic logic that can run without AutoCAD—calculations, decisions, validation, and transformations. But if a class mostly forwards values to AutoCAD and coordinates API calls, wrapping every property may add ceremony without much benefit. In that case, keep the AutoCAD-facing code straightforward and cover the important workflows with integration or functional tests.
The color example is a good warning sign. If the rule is mainly “set this AutoCAD property based on that AutoCAD property,” forcing it through another interface may just duplicate the API. I’d extract the logic only when it becomes complex enough to benefit from independent testing.

Realistic scenarios have another advantage: they catch changes in the external API that mocks cannot. I’d prioritize a reliable integration-test setup first, then extract and unit-test only the logic that proves difficult or slow to exercise through AutoCAD.