Unit testing a private method that loads a public property

6 posts, 0 answers
  1. Greg
    Greg avatar
    16 posts
    Member since:
    Sep 2013

    Posted 23 Oct 2013 Link to this post

    I am testing a private method using JustMock and that works fine. However, to verify the method worked correctly, I need to pull the value of a public property that the private method loads. Basically, the constructor loads a set of configuration XML documents and exposes them through a public property of a configuration class. 

    So I am able to mock the private method that is executed from the contrstructor (InitializeFile) and it works fine.  But I want to create a couple of asserts to verify the public property has the values that it should and that it is not empty. But since I have mocked a private method, I don't have a way to get to the public property. At least I do not see how to do that and none of the examples I have come across this show this.

    Here's the test I have come up with so far.  The GetProperty() fails becuase the property is a public property and I have mocked up a PrivateAccessor.  So what do you have to do to mock a priviate method, but also have access to get the value of a public property... or can you with JusMock?

     public void LoadConfiguartionSettingsTest()
     {
         // Arrange
         var inst = PrivateAccessor.ForType(typeof(Configuration));
         var xdoc = (XDocument)inst.CallMethod("InitializeFile");

         
    // Act
         inst.CallMethod("LoadConfiguartionSettings", new object[] { xdoc });
         var resp = inst.GetProperty("AppSettings");  // This fails... I guess because it is a public property.

         
    // Assert
         Assert.IsNotNull(resp);
         Assert.IsInstanceOfType(resp, typeof(List<AppSetting>));
     }
  2. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 24 Oct 2013 Link to this post

    Hi Greg,

    Thank you for contacting us.

    You should be able to call public members with the JustMock's Private Accessor. I executed your test with the following system under test:
    public class AppSetting
    {
    }
     
    public class XDocument
    {
    }
     
    public static class Configuration
    {
        private static void LoadConfiguartionSettings()
        {
            AppSettings = new List<AppSetting>();
        }
     
        private static XDocument InitializeFile()
        {
            return new XDocument();
        }
     
        public static List<AppSetting> AppSettings { get; set; }
    }
    and it passed.

    However, as it is possible to call public members via the Private Accessor in most of the cases this is not needed. For example, I wrote the same test method like this:
    [TestMethod]
    public void LoadConfiguartionSettingsTest()
    {
        // Arrange
        var inst = PrivateAccessor.ForType(typeof(Configuration));
        var xdoc = (XDocument)inst.CallMethod("InitializeFile");
     
        // Act
        inst.CallMethod("LoadConfiguartionSettings");
        var resp = Configuration.AppSettings;
     
        // Assert
        Assert.IsNotNull(resp);
        Assert.IsInstanceOfType(resp, typeof(List<AppSetting>));
    }
    and it passed again.

    Please, let me know if your system under test is somehow different and this does not work. In such case, I will be happy to assist you further on the matter.

    Regards,
    Kaloyan
    Telerik
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  3. DevCraft R3 2016 release webinar banner
  4. Greg
    Greg avatar
    16 posts
    Member since:
    Sep 2013

    Posted 24 Oct 2013 Link to this post

    Thanks for your feedback and sample code.  Seeing that it works for you helped me to identify my issue.  It looks like the issue is just that my property is actually not a property... but just a public field. I flipped it to a property and it works fine.  Also, I did not have the static accessor in the class name, as in C# it is not required if all of the methods and properties are static, the class is static.  However, I can see that JustMock cannot see that.  So I set to static and not use the default accessor so JustMock would see it.

    But I am still having issues.  So I adjusted this to show you what is going on.  I adjusted the code to load a small configuration XML string and use that in the LoadConfigurationSettings method call.  With my fake config file I only have 3 appSettings.  The real one has 79 appSettings.  So now when the LoadConfigurationSettings method is called, I pass in the fake 3 appSetting config XML document.  However, it still loads the 79 from the real file.  I think that means that when I call LoadConfiguraitonSettings(), as new instance of the configuration class is created, the non-faked version of the configuration is loaded, and that is what is returned to be verified in my unit test.  However, the point of the unit test is to not depend on the real config.xml file. So the fake one is what I need to work.  However, I cannot figure out what JustMock is doing here and how to correct it. I have tried working through a number of difference ways to mock this based on the online samples.  But this is the only one that seems to work for a static class.  But I still cannot resolve the last issue, which is to use my fake XML document.  It always loas the real one. 

    Any ideas what JustMock is doing here?  I do not understand what is going on and how to get it to work correctly.

               public void LoadConfiguartionSettingsTest()
            {
                // Arrange
                var inst = PrivateAccessor.ForType(typeof(Configuration));
      
                // Act
                inst.CallMethod("LoadConfiguartionSettings", new object[] { GetConfigFile() });
                var resp = inst.GetProperty("AppSettings");
      
                // Assert
                Assert.IsNotNull(resp);
                Assert.IsInstanceOfType(resp, typeof(List<AppSetting>));
             }

    Here's the GetConfigFile() that just loads a fake XML document with only 3 appSettings.

    private XDocument GetConfigFile()
    {
        string xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><configuration><appSettings key=\"GSA_Comments\" value=\"Additional Comments\" /><appSettings key=\"GSA_Address1\" value=\"Address 1\" /></configuration>";
        return XDocument.Parse(xmlString);
    }

    Here's the actual configuraiton class with comments and extra fluff removed.

          public class Configuration
        {
            public static List<AppSetting> AppSettings { get; set; }
            public static string AppPath { get; set; }
      
            static Configuration()
            {
                AppSettings = new List<AppSetting>();
                XDocument xdoc = InitializeFile();
                LoadConfiguartionSettings(xdoc);
            }
      
            private static XDocument InitializeFile()
            {
                var configFile = "";
                AppPath = HostingEnvironment.ApplicationPhysicalPath;
                if (string.IsNullOrEmpty(AppPath)) // local debugging
                    AppPath = @"C:\Projects\Source\Data\"  
                try
                {
                    configFile = Path.Combine(AppPath, "config.xml");
                    return XDocument.Load(configFile);
                }
                catch (System.Exception ex)
                {

                        throw

     

     

    new IOException(string.Format("Could load config.xml into XML document. Path: {0} Error: {1}", AppPath, ex.Message));

     

                }
            }
      
            private static void LoadConfiguartionSettings(XDocument xdoc)
            {
                var query = (from attrib in xdoc.Descendants("configuration").Descendants("appSettings")
                             select new AppSetting
                             {
                                 Key = attrib.Attribute("key").Value,
                                 Value = attrib.Attribute("value").Value
                             }).ToList();
      
                foreach (var item in query)
                {
                    AppSetting ap = new AppSetting();
                    ap.Key = item.Key;
                    ap.Value = item.Value;
                    AppSettings.Add(ap);
                }
            }
      
            public static string GetAppSetting(string strKey)
            {
                var ret = (from item in AppSettings
                           where item.Key == strKey
                           select item.Value).FirstOrDefault();
                return ret;
            }
      
        }
  5. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 25 Oct 2013 Link to this post

    Hi Greg,

    Thank you for the detailed information provided. It really helps to investigate the matter faster :).

    I was able to reproduce the issue. Debugging the test method, I noticed that the static constructor of the Configuration class was invoked. As it is calling the InitializeFile() and the LoadConfigurationSettings() methods, with a default values (in your case the real config.xml file), it was causing the issue.

    To prevent this, I added a SetupStatic function which mocks the static constructor and in the same time sets CallOriginal behavior. More about this can be found here. Further, I also needed an initialization of the AppSettings property (to prevent a NullReferenceException at the end of the LoadConfigurationSettings method). The final test looks like this:
    [TestMethod]
    public void LoadConfiguartionSettingsTest()
    {
        // Arrange
        Mock.SetupStatic(typeof(Configuration), Behavior.CallOriginal, StaticConstructor.Mocked);
        Configuration.AppSettings = new List<AppSetting>();
         
        var inst = PrivateAccessor.ForType(typeof(Configuration));
     
        // Act
        inst.CallMethod("LoadConfiguartionSettings", new object[] { GetConfigFile() });
        var resp = inst.GetProperty("AppSettings");
     
        // Assert
        Assert.IsNotNull(resp);
        Assert.IsInstanceOfType(resp, typeof(List<AppSetting>));
    }
    It passes. Also, after getting the AppSettings property, you can see that the resp.Count is actually 2.

    I hope this helps and works as expected on your side. Let me know if I can be of a further assistance.

    Regards,
    Kaloyan
    Telerik
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  6. Greg
    Greg avatar
    16 posts
    Member since:
    Sep 2013

    Posted 25 Oct 2013 Link to this post

    Works perfectly!  That makes complete sense and works exactly as it I need to.  Thanks for taking the time to resolve this for me.

    I'll read through the static mocking link that you provided, as most of my problems is just not being familiar with JustMock and how things are done.  Step by step I am catching on.  Thanks for pointing me in the right direction here.

    Best regards,
    Jon
  7. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 25 Oct 2013 Link to this post

    Hi Greg,

    Great to hear that!

    I believe the best source to get familiar with JustMock is our online help documentation. There are articles for all the JustMock features and functionalities. Another good source are the shipped with JustMock example solutions. You can find the in the JustMock install folder, under Examples\. Note, there C# and VB.NET examples there.

    Also, I will be happy to assist you if you have more questions or issues. So, do not hesitate to contact our support services.

    Have a nice day and happy mocking :).

    Regards,
    Kaloyan
    Telerik
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
Back to Top
DevCraft R3 2016 release webinar banner