views:

88

answers:

4

I have to Unit Test a method (runMethod()) that uses a method from an inhereted abstract class to create a boolean. The method in the abstract class uses XmlDocuments and nodes to retrieve information. The code looks somewhat like this (and this is extremely simplified, but it states my problem)

namespace AbstractTestExample
{
public abstract class AbstractExample
{
    public string propertyValues;
    protected XmlNode propertyValuesXML;
    protected string getProperty(string propertyName)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(new System.IO.StringReader(propertyValues));
        propertyValuesXML= doc.FirstChild;

        XmlNode node = propertyValuesXML.SelectSingleNode(String.Format("property[name='{0}']/value", propertyName));
        return node.InnerText;
    }
}

public class AbstractInheret : AbstractExample
{
    public void runMethod()
    {
        bool addIfContains = (getProperty("AddIfContains") == null || getProperty("AddIfContains") == "True");
        //Do something with boolean
    }
}
}

So, the code wants to get a property from a created XmlDocument and uses it to form the result to a boolean. Now my question is, what is the best solution to make sure I have control over the booleans result behaviour. I'm using Moq for possible mocking.

I know this code example is probably a bit fuzzy, but it's the best I could show. Hope you guys can help.

EDIT: What I basically need is:
I need to be able to control getProperty() while im testing the AbstractInheret class

A: 

If I understand your question correctly, you want to know how to control the result of getProperty so that you can test addIfContains with different boolean values.

If you are having difficulty writing a test for something, it often means you are trying to test too much, or that there is a problem with the design of the code.

You might be able to make this code more testable by avoiding the use of inheritance. As you have discovered, inheritance is often hard to handle in unit tests (there is a lot of tight-coupling going on), and delegation usually works better anyway. I'd recommend making the following change to the design:

namespace TestExample
{
    public interface PropertyManager {
      public string getProperty(string propertyName);
    }

    public class XmlPropertyManager: PropertyManager {
      public string getProperty(string propertyName) {
      //...xml parsing code here
      }
    }

    public class Example {
      private PropertyManager propertyManager;

      public void runMethod() {
        bool addIfContains = (propertyManager.getProperty("AddIfContains") == null || propertyManager.getProperty("AddIfContains") == "True");
        //Do something with boolean
      }
    }
}

Then you can easily mock out PropertyManager.

If your design requires that you use an abstract base class (for other functions other than just getProperty), you can still use the delegate approach:

namespace TestExample
{
    public interface PropertyManager {
      public string getProperty(string propertyName);
    }

    public class XmlPropertyManager: PropertyManager {
      public string getProperty(string propertyName) {
      //...xml parsing code here
      }
    }

    public abstract class AbstractExample
    {
       protected PropertyManager propertyManager;

       //... other important methods
    }

    public class AbstractInheret: AbstractExample {

      public void runMethod() {
        bool addIfContains = (propertyManager.getProperty("AddIfContains") == null || propertyManager.getProperty("AddIfContains") == "True");
        //Do something with boolean
      }
    }
}
Jim Hurne
Interesting approach you got there jedijim :] I like it, not sure if I can use it in my implementation though. I'll give it a try. If it does work, I'll let you know/accept your answer. Thanks for the reply!
Bas
I moved the alternative approach to another answer so that it will be clear which solution you choose to use. I also added an example of how you can use a delegate and still use an abstract base class.
Jim Hurne
I followed up JJoos his example and it came up with the solution of using an Dictionary. Using the propertyName as key and the propertyValue as it's value :] Now im not using getProperty("key") anymore but Dictionary["key"]. Thank you for your feedback though! It did help but I had to refactor to much code for it >.<
Bas
A: 

I am not very sure what exactly you mean by this question -

"what is the best solution to make sure I have control over the booleans result behaviour."

I am guessing that you need the boolean value of a property. So, this might just do!

    public static bool GetBoolean(string boolStr)
    {
        bool bVal = default(bool);
        try
        {
            bVal = Convert.ToBoolean(boolStr);
        }
        catch (Exception) {
            bVal = default(bool);
        }
        return bVal;
    }

Just plug it in code and it should be good. :)

Nayan
Getting the boolean is not the problem :] The problem is: How can I control it's outcome. Because of the dependency's I can't say in my test: addIfContains = true or addIfContains = false. This is where I need to mock/stub something. And my question thus is: How do you approach that while my class is using a method inhereted from an abstract class and is using Xml dependency which is not being injected.
Bas
I'm afraid I'm unable to understand your problem. Only if there was more details about 'dependencies' and 'need to mock'...
Nayan
Well I have to agree with ya, the situation which I'm trying to explain is also difficult (and hard to explain in a simple context). But what I'm basically looking for is something like jedijim proposed. I need to be able to control getProperty() while im testing the AbstractInheret class
Bas
"How" do you want to control function getProperty?
Nayan
Interface/Mock or by refactoring. This is only for Unit Testing purpose
Bas
+1  A: 

Since the value of the boolean is controlled by the xml, you could refactor your code, so you can easily set the xml.

Like this:

namespace AbstractTestExample
{
    public abstract class AbstractExample
    {
        protected XmlNode propertyValuesXML;

        protected string getProperty(string propertyName)
        {
            XmlNode node = propertyValuesXML.FirstChild.SelectSingleNode(String.Format("property[name='{0}']/value", propertyName));
            return node.InnerText;
        }
    }

    public class AbstractInheret : AbstractExample
    {
        public AbstractInheret(string propertyValues){

            propertyValuesXML = new XmlDocument();
            propertyValuesXML.Load(new System.IO.StringReader(propertyValues));
        }

        public void runMethod()
        {
            bool addIfContains = (getProperty("AddIfContains") == null || getProperty("AddIfContains") == "True");
            //Do something with boolean
        }
    }
}

This way you don't have to mock anything and you could easily pass a string of xml to your class. You should also check for error condition involving not valid xml passed to the constructor.

JJoos
A: 

If for some reason you cannot refactor your code in the way described in my first answer (such as a third party is providing the abstract base class), then you can create a subclass of AbstractInherit that overrides just the getProperty method. Note that I really don't like that type of approach, as it couples your tests to the internal implementation of the class. But sometimes you have no choice.

Jim Hurne