This project is read-only.

My first XAT

Jan 24, 2012 at 5:17 PM

Hi.

I am needing to get started with XATs, but have a few questions.

I have successfully done the below on one of my domain objects:

SetUser("sven");

ITestObject org = GetTestService ("Admin").GetAction ("New Organisation", "Organisations").InvokeReturnObject ();

The first question I have, is how do I save this entity now as if the user saved it?

 

Secondly, I see the above way is for testing the domain model from the user's perspective. However. Before testing it though, I need to do some entity / data preparation to get the domain model into the correct state that I want to test. (I will be testing against a database)

Hence is there a way to get hold of a Container so that I can do a bunch of preparation for my tests against strongly typed entities and to persist them?

Thank you much

Jan 24, 2012 at 6:49 PM

"The first question I have, is how do I save this entity now as if the user saved it?"

org.Save();

"Before testing it though, I need to do some entity / data preparation to get the domain model into the correct state that I want to test. (I will be testing against a database)"

If you are testing against a database then my advice is to set up the database to its initial state outside the Test project  -  either directly on the database or by writing a mini runtime application that has a method to set up the entities programmatically,  then snapshot (back-up) the database.  Hopefully you have already found the instructions for restoring the database to a particular snapshot each time the testFixture is run.  This is what we do with many of our framework tests.

(If you are running tests with objects in memory, rather than a database, then you can use a Fixture to do the set-up  -  which does have a Container injected.)

 

Jan 24, 2012 at 7:40 PM

Thank you for the quick feedback.

"org.Save();"

Ok. I feel a bit silly now. :) I only examined the methods defined on the ITestObject interface, in stead of going higher up the hierarchy.

"If you are testing against a database then my advice is to set up the database to its initial state outside the Test project  -  either directly on the database or by writing a mini runtime application that has a method to set up the entities programmatically,  then snapshot (back-up) the database.  Hopefully you have already found the instructions for restoring the database to a particular snapshot each time the testFixture is run.  This is what we do with many of our framework tests."

Yes, I saw the snapshot option. However, snapshots are not available on SQL Express, and some developers working on this project only has that. And the DB restore option is too slow.

I really would like to integrate the preparation and cleanup work directly into the test run. Another thing, for some actions on entities, that contain complicated business logic, I am not so much concerned with the user perspective (I will test that in another test), but rather in verifying that the results of running the action on the entity are correct in the database.

In other test projects that I have written, I used 2 data context instances. One to do the data prep, the verification checks of the test, and the data cleanup, and the second used by the actual code I was testing.

Now, I could do the data prep and checks with direct ADO or something, but a lot of the prep logic is already encapsulated in my domain model. I was hoping I could use it to do that.

Basically I want to boot up a second NakedObjects Container distinct from the other one that is already there. Any tips?

Jan 25, 2012 at 10:53 AM

Yes, the database restore option is slow  -  in our case it can take an hour to run the full suite of database integration tests  -  so we tend to run those on the build server on a regular schedule.  But I do think this is the right approach.  You can keep those separate from your unit tests and/or in-memory XATs, which you can afford to run much more often.

The alternative is that you can do your setup within the initialise method of the test, using the same constructs as the tests themselves.  (It might be necessary to put transaction boundaries in to ensure that the objects are persisted and available to queries in the test  -  I can't remember off-hand whether the initialize method is called as a separate transaction or not.  Try it out  -  and see other recent discussions about manually setting transaction boundaries.

But if you are working with the database and you do set up each time then you will have to tear them all down correctly  -  even if the tests have failed before completion and the database has been left in an unknown state.  It's a nightmare.  My advice it still to use the database restore approach, and adjust your development cycle accordingly.

 

 

Jan 26, 2012 at 4:38 AM

Thanx.

"The alternative is that you can do your setup within the initialise method of the test, using the same constructs as the tests themselves."

The test constructs are a bit cumbersome to use for data prep.

 

"But if you are working with the database and you do set up each time then you will have to tear them all down correctly  -  even if the tests have failed before completion and the database has been left in an unknown state.  It's a nightmare.  My advice it still to use the database restore approach, and adjust your development cycle accordingly."

The database happened to be structured in a way to facilitate easy tear down with a stored procedure, and that is already written.

Jan 26, 2012 at 8:23 AM
Edited Jan 26, 2012 at 8:24 AM

Ok. So, convoluted as I am, I have found a way to get hold of the Container relevant to the test context so that I can do data prep with it. I like to do things the way it works in my head, unless I have been convinced otherwise. I haven’t yet. :) 

 

I’m sure this won’t carry your approval so much, Richard. :) I am equally sure there might be a much easier or better way of getting the Container, but I haven’t discovered it.

 

Anyhow, if anybody else is interested in doing data prep  for your XAT, or other, tests, using your existing domain model, here is How I did it.

 

I added a new Repository called TestRepository.

It contains the following nested class and 1 method:

 

                public class WrappedContainer

                {

                                public object Container

                                {

                                                get;

                                                set;

                                }

                }

 

                public WrappedContainer GetContainer ()

                {

                                var c = new WrappedContainer ();

                                // Wrap the Container.

                                c.Container = this.Container;

                                return c;

                }

We return a WrappedContainer instead of an IDomainObjectContainer because the latter breaks the Naked Objects because of some internals when we use the XAT test constructs to get a hold of it.

 

In the SystemServices property of our XAT class, we then register a new TestRepository().

 

The last step to expose the Container to your test class is to add the following property on the class:

 

                public IDomainObjectContainer Container

                {

                                get

                                {

                                                var objc = GetTestService (typeof (TestRepository)).GetAction ("Get Container").InvokeReturnObject ();

                                                var wrapped = (TestRepository.WrappedContainer)objc.GetDomainObject ();

                                                return (IDomainObjectContainer)wrapped.Container;

                                }

                }

 

Just remember to wrap your test data prep code in:

                NakedObjectsContext.ObjectPersistor.StartTransaction ();

and

                NakedObjectsContext.ObjectPersistor.EndTransaction ();

 

If you need to execute stored procs, you can also add the following property:

 

                /// <summary>

                /// Returns the underlying Object Context from the NakedObjects

                /// Container for allowing access to stored procedures and functions

                /// mapped in the model.

                /// </summary>

                public ObjectContext Context

                {

                                get

                                {

                                                /* Copied from NakedObjects manual:

                                                * 3.6.8. How to access the DB Context directly.

                                                * The DB Context is accessible by casting the results of the Container.Instances<T>() method

                                                * as an ObjectQuery. It is not important what type you make T (as long as it is one of your

                                                * domain entity types) as the resulting context is not typed. */

                                                return ((ObjectQuery)Container.Instances<Organisation> ()).Context;

                                }

                }

 

 

And there you have it.

 

But to make all of this easier, I have created a XatBase class from where all my other XAT classes inherit.

I moved all my “Run Configuration” region code into the base (I over ride them in the specific XAT classes if I need something different).

I also moved the Container and Context properties, explained above, to the base class, as well as the Initialize and Cleanup methods, and made them virtual.

 

Now we can create utility methods that create entities for testing and returns them to the XAT tests as needed. The utility methods also register each created object into a List<T> on the base class. That list is then used during cleanup to automatically delete the test data that was created.

 

In my case, everything I am testing hangs off an Organisation entity, therefore I only need to keep track of that. I have a stored procedure that does a cascading delete on the Organisation and all dependent records in the database based on the OrganisationId. So it makes clean up really easy and robust.

 

And that’s all for now. :)

 

Ok. So, convoluted as I am, I have found a way to get hold of the Container relevant to the test context so that I can do data prep with it. I like to do things the way it works in my head, unless I have been convinced otherwise. I haven’t yet. J

 

I’m sure this won’t carry your approval so much, Richard. J I am equally sure there might be a much easier or better way of getting the Container, but I haven’t discovered it.

 

Anyhow, if anybody else is interested in doing data prep  for your XAT, or other, tests, using your existing domain model, here is How I did it.

 

I added a new Repository called TestRepository.

It contains the following nested class and 1 method:

 

            public class WrappedContainer

            {

                        public object Container

                        {

                                    get;

                                    set;

                        }

            }

 

            public WrappedContainer GetContainer ()

            {

                        var c = new WrappedContainer ();

                        // Wrap the Container.

                        c.Container = this.Container;

                        return c;

            }

We return a WrappedContainer instead of an IDomainObjectContainer because the latter breaks the Naked Objects because of some internals when we use the XAT test constructs to get a hold of it.

 

In the SystemServices property of our XAT class, we then register a new TestRepository().

 

The last step to expose the Container to your test class is to add the following property on the class:

 

            public IDomainObjectContainer Container

            {

                        get

                        {

                                    var objc = GetTestService (typeof (TestRepository)).GetAction ("Get Container").InvokeReturnObject ();

                                    var wrapped = (TestRepository.WrappedContainer)objc.GetDomainObject ();

                                    return (IDomainObjectContainer)wrapped.Container;

                        }

            }

 

Just remember to wrap your test data prep code in:

            NakedObjectsContext.ObjectPersistor.StartTransaction ();

and

            NakedObjectsContext.ObjectPersistor.EndTransaction ();

 

If you need to execute stored procs, you can also add the following property:

 

            /// <summary>

            /// Returns the underlying Object Context from the NakedObjects

            /// Container for allowing access to stored procedures and functions

            /// mapped in the model.

            /// </summary>

            public ObjectContext Context

            {

                        get

                        {

                                    /* Copied from NakedObjects manual:

                                    * 3.6.8. How to access the DB Context directly.

                                    * The DB Context is accessible by casting the results of the Container.Instances<T>() method

                                    * as an ObjectQuery. It is not important what type you make T (as long as it is one of your

                                    * domain entity types) as the resulting context is not typed. */

                                    return ((ObjectQuery)Container.Instances<Organisation> ()).Context;

                        }

            }

 

 

And there you have it.

 

But to make all of this easier, I have created a XatBase class from where all my other XAT classes inherit.

I moved all my “Run Configuration” region code into the base (I over ride them in the specific XAT classes if I need something different).

I also moved the Container and Context properties, explained above, to the base class, as well as the Initialize and Cleanup methods, and made them virtual.

 

Now we can create utility methods that create entities for testing and returns them to the XAT tests as needed. The utility methods also register each created object into a List<T> on the base class. That list is then used during cleanup to automatically delete the test data that was created.

 

In my case, everything I am testing hangs off an Organisation entity, therefore I only need to keep track of that. I have a stored procedure that does a cascading delete on the Organisation and all dependent records in the database based on the OrganisationId. So it makes clean up really easy and robust.

 

And that’s all for now. J