This is a migrated thread and some comments may be shown as answers.

Unit testing a private method that loads a public property

5 Answers 243 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Greg
Top achievements
Rank 1
Greg asked on 23 Oct 2013, 07:53 PM
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>));
 }

5 Answers, 1 is accepted

Sort by
0
Kaloyan
Telerik team
answered on 24 Oct 2013, 10:18 AM
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.
0
Greg
Top achievements
Rank 1
answered on 24 Oct 2013, 02:52 PM
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;
        }
  
    }
0
Kaloyan
Telerik team
answered on 25 Oct 2013, 09:22 AM
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.
0
Greg
Top achievements
Rank 1
answered on 25 Oct 2013, 01:34 PM
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
0
Kaloyan
Telerik team
answered on 25 Oct 2013, 03:13 PM
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.
Tags
General Discussions
Asked by
Greg
Top achievements
Rank 1
Answers by
Kaloyan
Telerik team
Greg
Top achievements
Rank 1
Share this question
or