Wednesday 16 July 2014

From NUnit AppDomain, accessing properties and invoking methods on 'Serializable MarshalByRefObject TeamMentor objects' (hosted on Cassini's AppDomain)

After How fast do the 'NUnit-Cassini-driven' tests execute (on a full TM instance) it was time to start accessing internal TeamMentor objects from the NUnit AppDomain.

The main change I did was to add the [Serializable] and the MarshalByRefObject to the TeamMentor (TM) objects that I want to consume (i.e. access data and invoke methods) from NUnit tests.

Here is an example of what it looks like in one of the main TM's data classes:

UnitTest: Confirm_That_We_Can_Access_TM_StartUp_As_MarshalByRefObject

The first example (gist here) is a pretty cool UnitTest, that shows the kind TM objects that I am now able to get 'strongly typed object' references, which can then be used safely from inside the NUnit AppDomain (running the UnitTest):

UnitTest: Create_User_Via_MarshalByRefObject_Proxies

This second example (gist here) shows how I was able to create a new TM user by calling the respective extension method.

As you will see in Note 1 below, to get this to work correctly, I had to invoke the createUser Extension Method using the O2Proxy helper class (which will invoke that method from inside the Cassini AppDomain)

UnitTest: Confirm_That_We_Can_Access_Variables_Across_AppDomains_Using_Reflection

This third example (gist here) is a refactored version of the Confirm_That_We_Can_Access_Variables_And_Methods_Across_AppDomains test shown in the previous blog post (gist here) which was simplified by the fact that the TM_Config object is now passed ByRef versus ByValue

This now means that I am able to access just about all of TM's data and methods natively from inside NUnit tests running inside the NUnit AppDomain.

Execution times

In terms of performance, here are the timings for the 3 tests shown above using NCrunch:

... and here are the execution times using ReSharper:

Note 1: there are some really funky behaviours that can happen if we start invoking ExtensionMethods from the NUnit AppDomain, with MarshalByRef objects from the Cassini AppDomain.

Quite a lot works, but I was having a number of issues with Lists (since new objects where being created in the NUnit AppDomain and not on the Cassini AppDomain).

Here is an example of a script that didn't work (gist here):

Note 1: I also had some weird serialisation errors created by the fact that lambda methods will create an auto-generated hidden 'DisplayClass' like the one shown bellow

Here is the IL of the class shown above (which is hidden from the C# view in ILSpy)

To fix this, I replaced the Lamba methods with direct static methods (as shown below)

... which solved the serialisation error (by the fact that the 'DisplayClass' did not exist anymore)