[wix-users] Unit Test Deferred Custom Actions

Jon Earle earlej at hotmail.com
Wed Mar 21 08:05:59 PDT 2018


That is how we are testing (actually performing the installation)... but it would be helpful to test the code prior to assembling into an MSI + bootstrapper (I want to start unit testing the custom bootstrapper code as well).

________________________________
From: Hoover, Jacob <Jacob.Hoover at greenheck.com>
Sent: Wednesday, March 21, 2018 10:53 AM
To: Jon Earle; WiX Toolset Users Mailing List
Subject: RE: Unit Test Deferred Custom Actions


You could write a WIP if you think there is enough value in introducing an ISession interface to the session object, which would allow you to then mock a session on your end. Is it only the session or are there other classes?  Why not just run the installs on VM’s to test them?



From: Jon Earle [mailto:earlej at hotmail.com]
Sent: Wednesday, March 21, 2018 9:18 AM
To: Hoover, Jacob <Jacob.Hoover at greenheck.com>; WiX Toolset Users Mailing List <wix-users at lists.wixtoolset.org>
Subject: Re: Unit Test Deferred Custom Actions



Is there really no other way to accomplish this?

Got as far as this, but ran into a problem reassigning a logging function (we use the session.Log method to trace our CA's):

        private Session CreateSessionObject()

        {

            Session session;

            unsafe

            {

                session = (Session)FormatterServices.GetUninitializedObject(typeof(Session));

                //session = Session.FromHandle((IntPtr)1, true);

                // Replace the CustomActionData with a new list - the current one is null.

                var field = typeof(Session).GetField("customActionData", BindingFlags.Instance | BindingFlags.NonPublic);

                field.SetValue(session, new CustomActionData());

                session.CustomActionData.Add("INSTALLDIR", @"c:\temp\company\client");

                // Swap the logging method with a new one that avoid calling non-existent (for testing) MSI methods.

                var a = typeof(Session).GetMethod("Message", BindingFlags.Instance | BindingFlags.Public);

                var b = typeof(TestHelperMethods).GetMethod("Message", BindingFlags.Instance | BindingFlags.Public);

                RuntimeHelpers.PrepareMethod(a.MethodHandle);

                RuntimeHelpers.PrepareMethod(b.MethodHandle);

                if (IntPtr.Size == 4)

                {

                    Int64* inj = (Int64*)b.MethodHandle.Value.ToPointer() + 2;

                    Int64* tar = (Int64*)a.MethodHandle.Value.ToPointer() + 2;

#if DEBUG

                    byte* injInst = (byte*)*inj;

                    byte* tarInst = (byte*)*tar;

                    Int64* injSrc = (Int64*)(injInst + 1);

                    Int64* tarSrc = (Int64*)(tarInst + 1);

                    *tarSrc = (((Int64)injInst + 5) + *injSrc) - ((Int64)tarInst + 5);

#else

                    *tar = *inj;

#endif

                }

            }

            return session;

        }

When I run it, the line which assigns *tarSrc (right above the #else), fails with:

"Exception thrown: 'System.AccessViolationException' in CustomActionsTest.dll An exception of type 'System.AccessViolationException' occurred in CustomActionsTest.dll but was not handled in user code Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Any suggestions to continue?  I would like to pursue this if possible, as it means I can test the entire CA and not just the meat of the try{} block.

Would mean I could author my tests like:

        [TestMethod()]

        public void SomeCATest()

        {

            using (Session session = CreateSessionObject())

            {

                // Test code...

            }

        }

As you can see, it would be really clean ...

I'm using MS Test (with Visual Studio 2015) so, if I had my druthers, I would like to continue using that, but, I am not against using nunit or xunit if there is a way to mock the Session object along with some of the contained methods.

Cheers!
Jon

________________________________

From: Hoover, Jacob <Jacob.Hoover at greenheck.com<mailto:Jacob.Hoover at greenheck.com>>
Sent: Tuesday, March 20, 2018 11:18 AM
To: WiX Toolset Users Mailing List
Cc: Jon Earle
Subject: RE: Unit Test Deferred Custom Actions



Best bet would be to refactor your CA code to do all the MSI specific stuff (Session, etc) in one method, that would then pass the values in as var's to a function that doesn't require any MSI specific objects.  You could then run your unit against the non-msi methods.

-----Original Message-----
From: wix-users [mailto:wix-users-bounces at lists.wixtoolset.org] On Behalf Of Jon Earle via wix-users
Sent: Tuesday, March 20, 2018 10:05 AM
To: 'WiX Toolset Users Mailing List' <wix-users at lists.wixtoolset.org<mailto:wix-users at lists.wixtoolset.org>>
Cc: Jon Earle <earlej at hotmail.com<mailto:earlej at hotmail.com>>
Subject: [wix-users] Unit Test Deferred Custom Actions

We have a few custom actions, set as deferred, which perform various things (create files, install or cleanup certificates, selectively update config files, etc).

I would like to write some unit tests for those.  Problem is, how do I deal with the Session object?  It does not appear to be instantiable... so, short of refactoring my CA code, how can I create a mocked up version of this that I can update and pass to my CAs?

____________________________________________________________________
WiX Toolset Users Mailing List provided by FireGiant http://www.firegiant.com/



More information about the wix-users mailing list