Best practice for creating a ReadOnlyListBase object for a unit test

Best practice for creating a ReadOnlyListBase object for a unit test

Old forum URL: forums.lhotka.net/forums/t/10436.aspx


Doug Ramirez posted on Monday, June 13, 2011

I'm interested to hear about what other people have done when instantiating a ReadOnlyListBase object for a unit test.  For example, I have a couple of command objects that use readonly lists.  I am finally getting around to creating unit tests for the command objects.  The command object accepts a readonly list as a param, so I need to create a readonly list with some test data, but I can't because, well, it's readonly.

I tried using private accessors but that really doesn't work because the command object doesn't accept MyList_Accessor as a param, for example.

I thought about adding some test helpers methods to the RO list, but that is clearly a hack that I don't want to propagate.

Any advise is greatly appreciated.  Code snippets, if applicable, are much appreciated too.

Doug

Doug Ramirez replied on Tuesday, June 14, 2011

Anyone have any good ideas about this?

JonnyBee replied on Tuesday, June 14, 2011

You could build "test" objects using an ObjectFactory derived class to generate the lists or different versions of the list.

Rocky recommends to use "public" constructors and when combined with ObjectFatory will give you easy code.

ObjectFactory class provides access to:

and more ....

Example:

    public class MyReadOnlyList : ReadOnlyListBase<MyReadOnlyList, MyReadOnlyChild>
    {
    }
        
    public class MyReadOnlyChild : Csla.ReadOnlyBase<MyReadOnlyChild>
    {
        public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
        public string Name
        {
          get { return GetProperty(NameProperty); }
        }
    
        public static readonly PropertyInfo<int> Num1Property = RegisterProperty<int>(c => c.Num1);
        public int Num1
        {
          get { return GetProperty(Num1Property); }
        }
    }
    
    public class MyTestGenerator : ObjectFactory
    {
        public MyReadOnlyList GetTestList1()
        {
            var list = new MyReadOnlyList();
            SetIsReadOnly(list, false);
            
            var child1 = new MyReadOnlyChild();
            LoadProperty(child1, MyReadOnlyChild.NameProperty, "jonny");
            LoadProperty(child1, MyReadOnlyChild.Num1Property, 99);
            
            list.Add(child1);

            SetIsReadOnly(list, true);
            return list;
        }
    }

Doug Ramirez replied on Tuesday, June 14, 2011

Thank you so much for the quick answer.  

I see how this will work.  It will require adding test code to the production library.  And subsequently making the child object's properties public.  Other than that, I think this will work.  

In my case I created a separate MyReadOnlyTestList class file (.cs) and placed the class in it.  I also had to use the factory methods to create the list and child object since those constructors are private (make sense?) and so I couldn't new them up.

I'd still be interested in knowing if someone has a clever way to do this without doing anything to the BOs.  I envision a scenario where someone would hand me a .dll and say "Here ya' go, write some tests for my library".

Doug

RockfordLhotka replied on Tuesday, June 14, 2011

The Using CSLA 4: Data Access ebook shows a couple ways to load objects using mock data - and the reason for that is to enable test scenarios.

The object factory approach is one - and if you are using modern coding styles you don't need to have public setters. You can also use a pluggable data layer with the DataPortal_XYZ methods, and so preserve encapsulation in a more obvious way.

JonnyBee replied on Wednesday, June 15, 2011

Even if your BO's constructor is private you can still create instances using:

var list = (MyReadOnlyList) Activator.CreateInstance(typeof(MyReadOnlyList);
or
var list = (MyReadOnlyList) MethodCaller.CreateInstance(typof(MyReadOnlyList));

or you could even make all your constructor public.

I'd still recommend to make the static PropertyInfo objects public readonly in scope.

The MyTestGenerator class can be places in your unit test project so you shouldn't need to add test code in the production library..

With ordinary editable objects - ObjectFactory exposes the BypassPropertyChecks that will allow you to load values into the BO as well as LoadProperty.
ReadOnly objects on the other will either have to use LoadProperty or expose a method to set internal field values.

Copyright (c) Marimer LLC