Today’s post will be rather quick. I will show you how a unit/integration test class that can interact with real model data in Sparx Enterprise Architect.
Beyond the well known Interop.EA
assembly there is another assembly called SparxSystems.Repository
that provides the intersting feature to connect to a running EA instance: Services.GetRepository()
. We can use this to write unit/integration tests that are run out of Visual Studio and the preferred test runner of our choice. Here is a test base class which will connect to a running EA instance and (if none is found) create a new EA instance (which of course will take some time):
public abstract class RepositoryTestClassBase : IDisposable { private const string EA_PROCESS_NAME = "EA"; private const string REPO_FILENAME = "Test.eap"; private const string REPO_RELATIVE_PATHNAME = "."; private static readonly object _syncRoot = new object(); protected static string RepoPathAndFileName { get; set; } = Path.Combine(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).AbsolutePath, REPO_RELATIVE_PATHNAME, REPO_FILENAME); private static readonly List _cleanupActions = new List(); private static int _instances; private static readonly Lazy _repository = new Lazy(() => { foreach (var process in Process.GetProcessesByName(EA_PROCESS_NAME)) { var repository = Services.GetRepository(process.Id); if(null == repository?.ConnectionString) continue; if(!repository.ConnectionString.EndsWith(REPO_FILENAME)) continue; return repository; } var result = new global::EA.Repository(); var isOpen = result.OpenFile(RepoPathAndFileName); _cleanupActions.Add(() => result.Exit()); result.ShowWindow(1); return result; }); protected static global::EA.Repository Repository => _repository.Value; private void ReleaseUnmanagedResources() { if (0 != Interlocked.Decrement(ref _instances)) return; _cleanupActions.Reverse(); foreach (var action in _cleanupActions) { action.Invoke(); } } protected virtual void Dispose(bool disposing) { ReleaseUnmanagedResources(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected RepositoryTestClassBase() { Interlocked.Increment(ref _instances); if (_repository.IsValueCreated) return; lock (_syncRoot) { if (_repository.IsValueCreated) return; var result = _repository.Value; } } ~RepositoryTestClassBase() { Dispose(false); } }
The valuefactory of _repository
will check if there is already a running instance of EA to connect to that matches the model file defined at the top of the class. If none is found a new instance will be created which will later automatically be closed after all tests are run (tracked by a synchronised invocation counter). If the instance was already running, it will be left as is.
With this class we can create unit/integration tests as easy as this:
[TestClass] public class IntegrationTest : RepositoryTestClassBase { [TestMethod] public void Test() { // Arrange // Act var result = Repository.ConnectionString; // Assert Assert.IsFalse(string.IsNullOrWhiteSpace(result)); } }