Geeks With Blogs

News Awarded Microsoft MVP C#.NET - 2007, 2008 and 2009


I am born in Bangladesh and currently live in Melbourne, Australia. I am a Microsoft Certified Application Developer MCAD Chartered Member (C# .Net)and born in Bangladesh.
I am founder and Chief Executive Officer of
Simplexhub, a highly experienced software development company based in Melbourne Australia and Dhaka, Bangladesh. Co-founder and core developer of Pageflakes www.pageflakes.com.
Simplexhub, is on its mission to build a smart virtual community in Bangladesh and recently launched beta realestatebazaar.com.bd an ASP.NET MVC application written in C#.NET.


Some of My Articles
Flexible and Plugin based .Net Application..
Mass Emailing Functionality with C#, .NET 2.0, and Microsoft® SQL Server 2005 Service Broker'
Write your own Code Generator or Template Engine in .NET
Shahed Khan blog

Filling up Mock objects with random data is possibly one of the most time consuming and boring chapter of writing test cases. Let say we have the following classes and we want to write some mock objects.

SmartDataManagement - Microsoft Visual Studio

 

Mock Object Code Example

       private Client GetMockClient()
        {
            Client Client1 = new Client();
            Client1.FirstName = "Random String 6dc22d70-ad0c-4552-9c86-2925e723a326";
            Client1.LastName = "Random String 3e08dc98-495a-4a70-bff4-b7b21489b0d0";

            ClientAddress ClientAddress2 = new ClientAddress();

            ContactAddress ContactAddress3 = new ContactAddress();
            ContactAddress3.Address = "Random String e5957034-893b-4d2c-a29a-5b23e2561c00";
            ContactAddress3.Phone = "Random String 8d034e87-ece3-42b8-ae97-35fad1639f41";
            ContactAddress3.Mobile = "Random String 73a6abad-3268-4ae4-b01c-1732ab0f5f52";
            ClientAddress2.HomeAddress = ContactAddress3;

            ContactAddress ContactAddress4 = new ContactAddress();
            ContactAddress4.Address = "Random String 117ef00d-f29d-4697-97ae-123a6b56da4f";
            ContactAddress4.Phone = "Random String 8e4d0bbe-f470-4438-8940-06d9889e3943";
            ContactAddress4.Mobile = "Random String 6f0cba5c-5a88-4e5b-88ae-32a569cffa41";
            ClientAddress2.ShippingAddress = ContactAddress4;

            Client1.ClientAddress = ClientAddress2;

            Misc Misc5 = new Misc();
            Misc5.OrderDate = DateTime.Now;
            Misc5.Quaitity = 945515547;
            Misc5.DeliveryDate = DateTime.Now;

            Customer Customer6 = new Customer();

            CustomerDemographics CustomerDemographics7 = new CustomerDemographics();
            CustomerDemographics7.FirstName = "Random String 9b9542e6-2eb9-4ac8-bbd9-46272c8531b4";
            CustomerDemographics7.LastName = "Random String 275ca427-9373-41a7-8249-9a3fd94631bd";

            ContactAddress ContactAddress8 = new ContactAddress();
            ContactAddress8.Address = "Random String c9d18341-cb7e-4086-ba09-76fd7eb09f71";
            ContactAddress8.Phone = "Random String d88849f2-f443-46b1-9d21-3eaed1739696";
            ContactAddress8.Mobile = "Random String 984cfe2b-c35e-46f4-8eb1-27342d3e21b2";
            CustomerDemographics7.HomeAddress = ContactAddress8;

            ContactAddress ContactAddress9 = new ContactAddress();
            ContactAddress9.Address = "Random String e67ae73f-8edd-47d1-add0-b1e84ddb6b05";
            ContactAddress9.Phone = "Random String 91b8d44e-3718-4cc7-be8a-194d308b8969";
            ContactAddress9.Mobile = "Random String a0d19e07-2b80-4f7a-acd2-7a507455c000";
            CustomerDemographics7.ShippingAddress = ContactAddress9;

            Customer6.CustomerDemographics = CustomerDemographics7;

            Misc5.AlternativeCustomer1 = Customer6;

            Client1.Misc = Misc5;

            return Client1;

        }


As you can see we will need to spare significant amount of time to prepare a Mock object for "Client" class. But you will be happy to know that I did not write a single line of the code that I pasted above. Yes, I generated it using Reflection. Let me share that magical piece of code with you which can save you a heaps of time.

The Mock Helper

    public class MockHelper
    {
        public MockHelper()
        {
            this.MaxDepth = 100;
        }

        int index = 1;   

        Dictionary<string, string> keys = new Dictionary<string, string>();
        List<string> assemblyList = new List<string>();
        StringBuilder codeBuilder = null;

        public int MaxIndexValue { get; set; }
        public string Generate(object obj)
        {
            //Assembly List that we are interested in for recursive calls, add according to your need.
            assemblyList.Add("SmartDataManagement.Blog");

            codeBuilder = new StringBuilder();
            GenerateCode(obj, string.Empty);
            return codeBuilder.ToString();
        }       

        private void GenerateCode(object obj, string theKey)
        {         
            string instanceName = string.Format("{0}{1}", obj.GetType().Name, index);
            codeBuilder.AppendLine(String.Format("{0} {1} = new {0}();", obj.GetType().Name, instanceName));
            keys.Add(theKey, instanceName);
            //Iterate through the list of Public Properties of the object instance
            foreach (System.Reflection.PropertyInfo property in obj.GetType().GetProperties())
            {     
                //Decide to dig deeper, if a PropertyType belongs to the assemblies that we are interested in, we go deep.
                if (GoDeeper(property))
                {
                    index = index + 1;                  
                    //Avoid infinite Loop situation
                    if (index < this.MaxIndexValue)
                    {
                        object propertyInstance = property.GetValue(obj, null);                       
                        if (propertyInstance == null)
                        {
                            //Dynamically create Property Instance
                            propertyInstance = Activator.CreateInstance(property.PropertyType);
                            if (property.CanWrite)
                                property.SetValue(obj, propertyInstance, null);
                            string key = Guid.NewGuid().ToString();
                            codeBuilder.AppendLine();
                            //Recursive call
                            GenerateCode(propertyInstance, key);

                            codeBuilder.AppendLine(String.Format(@"{0}.{1} = {2};", instanceName, property.Name, keys[key]));
                            codeBuilder.AppendLine();
                        }
                    }
                }
                else if (property.PropertyType == typeof(string))
                {
                    codeBuilder.AppendLine(String.Format(@"{0}.{1} = ""{2}"";", instanceName, property.Name, GetRandomString()));
                }
                else if (property.PropertyType == typeof(DateTime))
                {
                    codeBuilder.AppendLine(String.Format(@"{0}.{1} = DateTime.Now;", instanceName, property.Name));
                }
                else if (property.PropertyType == typeof(int))
                {
                    codeBuilder.AppendLine(String.Format(@"{0}.{1} = {2};", instanceName, property.Name, GetRandomInt()));
                }
            }
        }

        private bool GoDeeper(PropertyInfo property)
        {
            //Dig deeper for interested Assemblies only, Please feel free to extend and put complex logics to serve your purpose.
            foreach (string assemblyName in assemblyList)
            {
                if (property.PropertyType.Assembly.FullName.Contains(assemblyName))
                    return true;
            }
            return false;
        }

        private string GetRandomString()
        { 
            return String.Format("Random String {0}", Guid.NewGuid().ToString());           
        }

        private int GetRandomInt()
        {
            byte[] buffer = Guid.NewGuid().ToByteArray();
            return BitConverter.ToInt32(buffer, 0);
        }
    }

The above code is self explanatory, I also commented to give an idea of how this is working, In short, I take an instance of the desired class, iterate through all of its Properties using Reflection and generate desired piece of code. While iterating, I also create property instance  as required and loop thorough the properties of the child in a recursive manner until all of them are served. The assemblyList object maintains the list of the assemblies that we are interested in for recursion.  Its worth mentioning the above piece of code has limitations, it will not work in the cases where there are circular references of Types for properties, that is why I kept a check for MaxIndexValue to break the infinite loop scenario.



SmartDataManagement - Microsoft Visual Studio (2) 

Fig, shows an example of circular references of Types, here Client has Misc property (of Type: Misc), and Misc has AlternativeClient1 property (of Type: Client).

The MockHelper has very simple logic to decide to create dynamic instances and to do recursive calls, it will get stuck within Client and Misc for this example. We can definitely overcome this by putting more complex logics and checks. I wanted to keep it simple and moreover it serves my purpose. Also here I cater with int, string and DateTime only, please feel free to extend to serve your purpose. You will notice I used StringBuilder above to accumulate the generated codes, but I normally use my SmartCodeGenerator and write simple templates for this kind of tricks, SmartCodeGenerator provides a lot more flexibility and comes with robust templating feature for purposes like this.

Usage


            MockHelper helper = new MockHelper();
            //Your desired class instance
            Client client = new Client();
            string code = helper.Generate(client);

Its quite simple to use the above helper, just create an instance of the MockHelper, then pass an instance of your desired class, it will return you the mock object code as we have seen above. Infact, the above piece of code can speed you up for any cases where you need to create instances of a class and need to write code to fill all its properties, moreover the generated code can also reduce chances of errors and typos that normally happens when we do it manually.

Thank you for being with me so far, hope this saves you some time, Happy coding :)

Posted on Wednesday, August 6, 2008 12:20 AM | Back to top


Comments on this post: Reflection Tips: Generate Mock objects for Test Cases.

# re: Reflection Tips: Generate Mock objects for Test Cases.
Requesting Gravatar...
Thanks admin adadas vxgergfscxvxvxvxvxcv
barbie oyunları
su pompası
Left by sesli sohbet on Sep 03, 2009 9:47 AM

Your comment:
 (will show your gravatar)


Copyright © Shahed Khan | Powered by: GeeksWithBlogs.net