Bilal+and+Abner+Project+2

1.0 Objective
toc

The objective of this project is to apply refactoring techniques found from chapter 3 to chapter 11 of the Refactoring book. The next sections will cover topics that will make your code cleaner and easier to understand and follow. We will also apply unit testing with NUnit to test the capabilities of the OrderersParser application that's using the NDigester API.

2.0 Self Encapsulated Field
Self Encapsulate Field technique is utilized when accessing a field is necessary to avoid coupling and to self-encapsulate, is to create getting and setting methods for the field. It is often assumed that when one use the setting method in the constructor for changes after the object is created, it may have different behavior in the setter than the ones initialized. In this case, a separate initialization method is used in the SetProperteryRule class as shown below:

code format="csharp" using System; using System.Text; using System.Reflection;

namespace DotnetPark.Commons.NDigester {   ///     /// Rule implementation that sets an individual property on the object at the /// top of the stack, based on attributes with specified names. ///    public class SetPropertyRule : Rule {       // The name of the attribute that will contain the name of the property to be set private string name = null;

// The name of the attribute that will contain the value to which the property should be set private string value = null;

///        /// Initializes a new instance of the SetPropertyRule class /// with the specified attribute name and attribute value. ///        /// The name of the attribute that will /// contain the name of the property to be set. /// The name of the attribute that will /// contain the value to which the property should be set. public SetPropertyRule(string name, string value) {           this.name = name; this.value = value; }

///        /// Process the start of this element. ///        public override void OnBegin {           // determine actual 'name' and 'value' string actualName = null; string actualValue = null;

for(int i=0; i<digester.Attributes.Count; i++) {               string name = digester.Attributes.GetKey(i); string value = digester.Attributes[i]; if(name == this.name) {                   actualName = value; }               else if(name == this.value) {                   actualValue = value; }           }

// populate object's property object top = digester.Peek; PropertyInfo prop = top.GetType.GetProperty(actualName, BindingFlags.Public | BindingFlags.Instance); prop.SetValue(top, Convert.ChangeType(actualValue, prop.PropertyType), null); }

///        /// Renders a printable version of this Rule. ///        /// The string that contains a printable version /// of this Rule. public override string ToString {           StringBuilder sb = new StringBuilder("SetPropertyRule["); sb.Append("name="); sb.Append(name); sb.Append(", value="); sb.Append(value); sb.Append("]"); return (sb.ToString); }   }

code

Code after Refactoring

code format="csharp" using System; using System.Text; using System.Reflection;

namespace DotnetPark.Commons.NDigester {   ///     /// Rule implementation that sets an individual property on the object at the /// top of the stack, based on attributes with specified names. ///    public class SetPropertyRule : Rule {       // The name of the attribute that will contain the name of the property to be set private string name = null;

// The name of the attribute that will contain the value to which the property should be set private string value = null;

///        /// Initializes a new instance of the SetPropertyRule class /// with the specified attribute name and attribute value. ///        /// The name of the attribute that will contain the name of the property to be set. /// The name of the attribute that /// will contain the value to which the property should be set. public SetPropertyRule(string name, string value) {           initialize(name, value); }

//separate intilization method is utilized private void initialize(string name, string value) {           this.name = name; this.value = value; }

// determine actual 'name' and 'value' string actualName = null; string actualValue = null;

///        /// Process the start of this element. ///        public override void OnBegin {

for(int i=0; i<digester.Attributes.Count; i++) {               string name = digester.Attributes.GetKey(i); string value = digester.Attributes[i];

if (name == getName) {                   setName;

}

else if (name == getValue) {

setValue; }           }

// populate object's property object top = digester.Peek; PropertyInfo prop = top.GetType.GetProperty(actualName, BindingFlags.Public | BindingFlags.Instance); prop.SetValue(top, Convert.ChangeType(actualValue, prop.PropertyType), null); }

// To self-encapsulate, getting and setting methods are utilized:

string getName {          return name; }

string getValue {          return value; }

void setName {          actualName = value; }

void setValue {          actualValue = value;

}

///        /// Renders a printable version of this Rule. ///        /// The string that contains a printable version /// of this Rule. public override string ToString {           StringBuilder sb = new StringBuilder("SetPropertyRule["); sb.Append("name="); sb.Append(name); sb.Append(", value="); sb.Append(value); sb.Append("]"); return (sb.ToString);

}

} }

code

The getting and setting method are created for the field and then all references to the field are located which are replaced with a getting or setting method. When using self-encapsulation, one has to be careful in using the setting method in the constructor to avoid having different behavior in the setter than the ones initialized and in this case, it is better to use either direct access from the constructor or separate initialization method.

2.1 Replace data value with Object
If there is a data item that needs additional behavior, then the data item needs to be converted into an object. For one or more item, putting the methods in to its own object can cause duplication of the code and when the smell begins, it is important to turn the data value into an object. In figure 2-1, the PropertySetterRule.cs has stored the propertyName as a string which is converted into an object and this way there is more space to store data such as property type, or property value.



The code for the PropertySetterRule.cs is shown below which takes in the name of the property:

code format="csharp" using System; using System.Text; using System.Reflection;

namespace DotnetPark.Commons.NDigester {   ///     /// Rule implements sets an object property on the top object of the Object Stack /// to the body text. ///   /// The property set: /// can be specified when the rule is created /// or can match the current element when the rule is called. ///    public class PropertySetterRule : Rule {       // The name of the property to set private string propertyName = null;

// The current grabbed body private string body = null;

///        /// Initializes a new PropertySetterRule class. ///        /// When using this constructor rule will set a property with /// a corresponding current element name. public PropertySetterRule : this(null) {           // use this }

///        /// Initializes a new PropertySetterRule class with the specified property name. ///        /// The name of the property to set. public PropertySetterRule(string propertyName) {           this.propertyName = propertyName; }

///        /// Process the body text of this element. ///        public override void OnBody {           body = digester.Body.Trim; }

///        /// Process the end of this element. ///        public override void OnEnd {           string property = propertyName;

if(property == null) {               // property was not specified // use the current element name property = digester.ElementName; }

// populate object's property object top = digester.Peek; PropertyInfo prop = top.GetType.GetProperty(property, BindingFlags.Public | BindingFlags.Instance); if(prop != null) {               prop.SetValue(top, Convert.ChangeType(body, prop.PropertyType), null); }       }

///        /// Renders a printable version of this Rule. ///        /// The string that contains a printable version of this Rule. public override string ToString {           StringBuilder sb = new StringBuilder("PropertySetterRule["); sb.Append("propertyName="); sb.Append(propertyName); sb.Append("]"); return (sb.ToString); }   } }

code First, the new property class is created called PropertyName.cs which contains a field of the same type as the value in the source class and it is called name. I also added a getting method and provide a constructor that uses the attribute as shown below: code format="csharp" using System; using System.Collections.Generic; using System.Text;

namespace DotnetPark.Commons.NDigester {   // creating the class for the value // adding a getter and a constructor that takes the field as an argument class PropertyName {       private string name;

public PropertyName(string name) {           this.name = name; }

public string getName {           return name; }   } }

code Since the field is mentioned in the source class constructor, the field is assigned using the constructor of the new class as shown below: code format="csharp" //changing the type of the propertyName field

public PropertySetterRule(string propertyName) {

PropertyName gettingProperty = new PropertyName(propertyName); this.propertyName = gettingProperty.getName;

}

code This finishes this refactoring, but in this case there is another step where if a property type is needed, it cannot be added into the code since the property name is treated as a value object. To give a property name this attribute, the following refactoring technique is utilized.

2.2 Change value to reference
Reference objects are things like property name or customer and value objects are like money or date which is defined entirely through their data values. The following figure 2-1 shows how the PropertrySetterRule.cs can be utilized to turn the object into a reference object:

The first step is replace constructor with factory method which takes control of the creation process as shown below: code format="csharp" public static PropertyName create(string name) {           return new PropertyName(name);

}

code The second step is to replace the calls to the constructor with calls to the factory in PropertySetterRule.cs: code format="csharp" public PropertySetterRule(string propertyName) {

PropertyName gettingProperty = PropertyName.create(propertyName);

this.propertyName = gettingProperty.getName;

}

code The next step is to access the property names by using another object and in this situation I created a registry object to be the access point. They are stored using a static field in a PropertyName.cs and therefore making it the access point. code format="csharp" private static Hashtable instances = new Hashtable; code The property names can be created in advance and they can come from a database or from a file. The loadPropertyName shown below contains two properties and it uses the store method to store them appropriately as shown below: code format="csharp" static void loadPropertyName {           new PropertyName("textBox").store; new PropertyName("TextAlign").store; } private void store {           instances.Add(this.getName, this); }

code The complete code for PropertyName.cs class is shown below which utilizes Rename Method technique and calls the factory method getProperty instead of create  since this method returns an existing property as shown below: code format="csharp" using System; using System.Collections.Generic; using System.Collections; using System.Text;

namespace DotnetPark.Commons.NDigester {   // Replace Constructor with Factory Method public class PropertyName {       private string name; private static Hashtable instances = new Hashtable;

public static PropertyName getProperty(string name) {           return new PropertyName(name);

}

private PropertyName(string name) {           this.name = name; }

static void loadPropertyName {           new PropertyName("textBox").store; new PropertyName("TextAlign").store; }       private void store {           instances.Add(this.getName, this); }

public string getName {           return name; }

public static PropertyName create(string name) {           return new PropertyName(name);

}

} }

code

2.3 Encapsulated Field
This is an important principle of object orientation or data hiding which says never make data public since when we make data public, other objects can change and access data values without the object’s knowing it. Encapsulate Field focuses on making the field private and providing accessors. The first step is to create getting and setting methods for the field and then determine whether clients uses the value or changes the value; once all clients are changed, the field can be declared as private. The following Client.cs class in NDigester is utilized where the getting and setting methods are added for the field called name. If the client uses the value, the reference is replaced with a call to the getting method and if the client changes the value, the reference is replaced with a call to the setting method as shown below:

code format="csharp" //making the public field to private private string name; // creating getting and setting methods for the field public string getName {           return name; }

public void setName(string value) {           name = value; }

code The complete code for the Client.cs is shown below where getting and setting methods for the field are created: code format="csharp" using System; using System.Text;

namespace OrdersParser {   ///     /// Summary description for Client. ///    public class Client {       private string name; private Address address; private string notes;

public Client {       }

// creating getting and setting methods for the field public string getName {           return name; }

public void setName(string value) {           name = value; }

public Address Address {           get { return address; } set { address = value; } }

public string Notes {           get { return notes; } set { notes = value; } }

public void SetAddress(Address address) {           this.address = address; }

public override string ToString {           StringBuilder sb = new StringBuilder;

sb.Append(name) .Append(", ") .Append(address.ToString) .Append("\nNotes: ") .Append(notes);

return sb.ToString; }   } }

code

3.1 Rename Method
This is an important part of the code style since renaming a method clarifies its intention and a good way to do this is to write the comment for the method first and then turning that comment into the name of the method. The following figure 3-1 improves the method name in PropertyName.cs so it can reveal its purpose as shown below: In the PropertyName.cs, the loadPropertyName is utilized which add new property names to the Hashtable as shown below: code format="csharp" static void loadPropertyName {           new PropertyName("textBox").store; new PropertyName("TextAlign").store;

}

code First I rename the method store to a more meaningful name called storeDataInHashTable so that the user can immediately know the purpose of that method as shown below: code format="csharp" static void GetPropertyName {           new PropertyName("textBox").storeDataInHashTable; new PropertyName("TextAlign").storeDataInHashTable; }

private void storeDataInHashTable {           instances.Add(this.getName, this); }

code In this step, I create the new method and copy the body over to the new method; the old method is now changes to call the new one as shown below: code format="csharp" static void loadPropertyName {           GetPropertyName; }

// obtain new property name static void GetPropertyName {           new PropertyName("textBox").storeDataInHashTable; new PropertyName("TextAlign").storeDataInHashTable; }

code

Now if there is a caller to the old method, it can be switched to call the new method and once all callers are switched, the old method can then be removed.

3.2 Parameterize method

If there are several methods that do similar things but vary depending on few values, they can be simplified further by replacing the separate methods with a single method which handles the variations by parameters. This technique can remove code duplication and it increases flexibility since other variations can be handled by adding parameters. The following figure 3-2 show how creating a parameterized method called PropertyType simplifies class further: The first step is to create a parameterized method called PropertyType which can be substituted for each repetitive method.

code format="csharp" static void PropertyType(string type) {           new PropertyName(type).storeDataInHashTable; }

private void storeDataInHashTable {           instances.Add(this.getName, this); }

code

The next step is to replace old methods with a call to the new method. The old methods for PropertyName.cs class are shown below:

code format="csharp" static void GetPropertyName {           new PropertyName("textBox").storeDataInHashTable; new PropertyName("TextAlign").storeDataInHashTable;

}

static void VariousProperties {           new PropertyName("Image").storeDataInHashTable; new PropertyName("ImageAlign").storeDataInHashTable; new PropertyName("ForeColor").storeDataInHashTable;

}

code

This can be replaced with:

code format="csharp" static void GetPropertyName {           PropertyType("Image"); PropertyType("TextAlign");

}

static void VariousProperties {           PropertyType("Image"); PropertyType("ImageAlign"); PropertyType("ForeColor");

}

code

Since the methods do similar things with different values, parameterize method can be utilized for each repetitive method.

4.1 Decompose Conditional
Decompose conditional is a method use to simplify conditional expressions by extracting the methods from it. Decompose conditional makes the intention of each logic clearer by taking the methods out of each if, else, then section and separating each one as their own method. The code below is from the NDigister open source library Rule.cs class. The Match method from that class contains conditional statements that can be refactored. The Decompose Conditional refactoring method can be used in this case to simplify the conditional expressions in the Match method. code format="csharp" public IList Match(string namespaceURI, string pattern) {           IList rulesList = Lookup(namespaceURI, pattern); if((rulesList == null) || (rulesList.Count < 1)) {               string longKey = ""; foreach(string key in cache.Keys) {                   if(key.StartsWith("*/")) {                       if(pattern.EndsWith(key.Substring(2))) {                           if(key.Length > longKey.Length) {                               rulesList = Lookup(namespaceURI, key); longKey = key; }                       }                    }                }            }            if(rulesList == null) {               rulesList = new ArrayList; }           return rulesList; }

code Below is the result of when I use the Decompose Conditional method to make the Match method look cleaner. But even after that more work is need to finish factoring the Match method. I made the if conditional into its own method called the NullRule method. code format="csharp" public IList Match(string namespaceURI, string pattern) {           if (NullRules(namespaceURI,pattern)) {               string longKey = ""; foreach(string key in cache.Keys) {                   if(key.StartsWith("*/")) {                       if(pattern.EndsWith(key.Substring(2))) {                           if(key.Length > longKey.Length) {                               rulesList = Lookup(namespaceURI, key); longKey = key; }                       }                    }                }            }            if(rulesList == null) {               rulesList = new ArrayList; }           return rulesList; }       public Boolean NullRules(string _namespaceURI, string _pattern) {           IList rulesList = Lookup(_namespaceURI, _pattern); return rulesList == null || rulesList.Count < 1; }

code

4.2 Consolidate conditional expressions
The Match method above can still be simplified some more by using the Consolidate Conditional Expressions refactoring method. The Consolidate Conditional Expressions refactoring method is basically consolidating like conditional expressions into one expression. The Match method if statements can be consolidated into one statement using this method. Below is the result of refactoring the Match method. The entire if statements were consolidated using the “&&” between conditions.

code format="csharp" public IList Match(string namespaceURI, string pattern) {           if (NullRules(namespaceURI,pattern)) {               string longKey = ""; foreach(string key in cache.Keys) {                   if (key.StartsWith("*/") && pattern.EndsWith(key.Substring(2)) && key.Length > longKey.Length) {

rulesList = Lookup(namespaceURI, key); longKey = key; }

}           }            if(rulesList == null) {               rulesList = new ArrayList; }           return rulesList; }       public Boolean NullRules(string _namespaceURI, string _pattern) {           IList rulesList = Lookup(_namespaceURI, _pattern); return rulesList == null || rulesList.Count < 1; }

code

4.3 Replace nested conditional with guard clauses

A way to refactoring conditional expressions is to replace the nested conditional with guard clause. A guard clause is a check on a condition and return if the condition is true. Replace the if and else statement with the guard clause. The result is clearer and better working code. Below is the ToString, I am going to use the replace nested conditional with guard clause method to refactor this method: code format="csharp" public override string ToString {           StringBuilder sb = new StringBuilder("CallMethodRule["); sb.Append("methodName="); sb.Append(methodName); sb.Append(", paramCount="); sb.Append(paramCount); sb.Append(", paramTypes={"); if (paramTypes != null) {               for (int i = 0; i < paramTypes.Length; i++) {                   if (i > 0) {                       sb.Append(", "); }                   sb.Append(paramTypes[i].Name); }           }            sb.Append("}"); sb.Append("]"); return (sb.ToString); }

code After refactoring the ToString method, the if and else statement inside the for loop is clearer and easier to understand.

code format="csharp" public override string ToString {           StringBuilder sb = new StringBuilder("CallMethodRule["); sb.Append("methodName="); sb.Append(methodName); sb.Append(", paramCount="); sb.Append(paramCount); sb.Append(", paramTypes={"); if (paramTypes != null) {               for (int i = 0; i < paramTypes.Length; i++) {                   if (i > 0) return sb.Append(", "); return sb.Append(paramTypes[i].Name); }           }            sb.Append("}"); sb.Append("]"); return (sb.ToString); }

code

4.4 Introduce Assertions
Introducing assertions helps to pin point exactly where an error occurs when debugging a code. The Assertion is introduced in parts of the code where only a certain condition will make that section of code work. An assertion is a conditional statement that is assumed to always be true. The ToString method from the section above will only work if the paramTypes are not equal to Null. Introducing an assertion to this section of code will throw an excpetion whenever the paramTypes are not true. Assertions are not part of the production code but should be used during the production phase to help track bugs. Below is the ToString method from NDigister CallMethodRule.cs class. The Assert.Istrue is added to check if the paramTypes is not null, if it is null it will throw an exception to let the coder know where the issue is. code format="csharp" public override string ToString {           StringBuilder sb = new StringBuilder("CallMethodRule["); sb.Append("methodName="); sb.Append(methodName); sb.Append(", paramCount="); sb.Append(paramCount); sb.Append(", paramTypes={"); Assert.IsTrue(paramTypes != null); if (paramTypes != null) {               for (int i = 0; i < paramTypes.Length; i++) {                   if (i > 0) return sb.Append(", "); return sb.Append(paramTypes[i].Name); }           }            sb.Append("}"); sb.Append("]"); return (sb.ToString); } code

5.0 Dealing with generalization
This section is about moving methods around a hierarchy of inheritance. Using the methods in this section will allow you to generalize your constructors, and also move methods from subclasses to the super classes.

5.1 Pull up constructor body
The Pull Up Constructor body is creating a superclass constructor for all the classes in your program if they all have similar bodies. The same why you can use the extract method to extract codes that does similar functions, you can also use the Pull Up Constructor method to extract the constructor from classes that have similar bodies. Below are the constructor from the rule abstract class and the constructor from the setpropertyrule class which is one of the subclasses: code format="csharp" public Rule {           digester = null; namespaceURI = String.Empty; }

public SetPropertyRule(string name, string value) {           this.name = name; this.value = value; }

code Using the Pull Up Constructor Body method, I add the common code from the subclass to the super class, then I will call the super class constructor as my first step in the constructor of my subclass, below is the result of applying this refactoring method to the class above: code format="csharp" protected Rule(string name, string value) {           digester = null; namespaceURI = String.Empty; this._name = name; this._value = value; }

public SetPropertyRule(string name, string value) {           Rule(name, value); }

code

5.2 Replace Inheritance with delegation
This section is about replacing inheritance with delegation. The idea is to not build an inheritance that the subclass is not using most of the methods or data from the super class. Delegation gives you the option to choose which part of inheritance you want to use and which parts you want to ignore. Below you have an abstract class calls RuleSet:

code format="csharp" public abstract class RuleSet {       ///         /// Holds the namespace URI that all Rule instances created by this RuleSet /// will be associated with. ///        protected string namespaceURI = null;

///        /// Gets or sets the namespace URI that all Rule instances created by this RuleSet /// will be associated with. ///        public string NamespaceURI {           get { return namespaceURI; } }

///        /// Add the set of Rule instances defined in this IRuleSet to the /// specified Digester instance, associating them with /// our namespace URI (if any). This method should only be called /// by a Digester instance. ///        /// The Digester instance to which the new Rule instances /// should be added. public abstract void AddRules(Digester digester);

public abstract void NotNeededRules(Digester digester); }

code I created a sub class that’s going to use the above class call AbnerClass. AbnerClass is using the methods that it needs and the ones that it doesn’t need from the RuleSet Class: code format="csharp" class AbnerClass : RuleSet {       public AbnerClass {       }

public override void AddRules(Digester digester) {           throw new NotImplementedException; }

public override void NotNeededRules(Digester digester) {           throw new NotImplementedException; }   }

code Replacing the inheritance with a delegation will allow the AbnerClass to only use the methods that it needs from the SetRule class. Adding delegation, now I can use the Add method without using the method that I don’t need.

code format="csharp" class AbnerClass {       private RuleSet _ruleSet = this; public AbnerClass {

}

public void AddRules(Digester digester) {           _ruleSet.AddRules(digester); }

}

code

5.3 Replace Inheritance with delegation
Replace Delegation with Inheritance is the opposite of what we did in the section above. If a sub class needs to use all the methods in a super class it would beneficial to use inheritance. Going the other way would just put the Abner class in its form shown below:

code format="csharp" class AbnerClass : RuleSet {       public AbnerClass {       }

public override void AddRules(Digester digester) {           throw new NotImplementedException; }

public override void NotNeededRules(Digester digester) {           throw new NotImplementedException; }   }

code

6.0 Unit Testing
NUNIT is an open source unit testing framework for .NET programming which can be used for .NET projects and in testing .dll files using a unit test class. Each testing method consists of the fixture (the thing to be tested such as Item), some operation to be tested such as, checking the item and evaluating the results as expected. The following are the test cases for Check Items class: The above test case is implemented using Nunit and it contains the following attributes: The following classes CheckItems.cs and Item.cs are shown below: code format="csharp" using System; using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework;
 * 1) The program verifies whether Item’s id, name and quantity are correct to ensure correct Items are requested by the user.
 * 2) The program tests the method called ToString in Item class and verifies the Item’s id, name and quantity.
 * 1) The [TextFixture] is used to indicate the test code written in a class.
 * 2) The [Test] is used to indicate a test to be performed.
 * 3) The StringAssert.AreEqualIgnoringCase is utilized to verify Items.

namespace TestCases {   [TestFixture]

public class CheckItems {       Item checkItem1; private string result;

private int id; private string name; private decimal qty;

[Test] // Testable method public void VerifyItem1 {

checkItem1 = new Item;

checkItem1.Id = 1001; checkItem1.Name = "10K Resistors"; checkItem1.Qty = 20;

StringBuilder sb = new StringBuilder; sb.Append("   Item #") .Append(id) .Append(" ") .Append(name) .Append(" ") .Append(qty);

result = sb.ToString;

StringAssert.AreEqualIgnoringCase(sb.ToString, result);

}

[Test] // Testable method

public void VerifyItem2 {           Item checkItem2 = new Item;

checkItem2.Id = 1002; checkItem2.Name = "470 Resistors"; checkItem2.Qty = 30;

StringBuilder sb = new StringBuilder; sb.Append("   Item #") .Append(id) .Append(" ") .Append(name) .Append(" ") .Append(qty);

result = sb.ToString;

StringAssert.AreEqualIgnoringCase(sb.ToString, result);

}

}

}

code Items.cs class code format="csharp" using System; using System.Collections.Generic; using System.Linq; using System.Text;

namespace TestCases {   class Item {

private int id; private string name; private decimal qty;

public Item {

}

public int Id       { get { return id; } set { id = value; } }

public string Name {           get { return name; } set { name = value; } }

public decimal Qty {           get { return qty; } set { qty = value; } }

public override string ToString {

StringBuilder sb = new StringBuilder; sb.Append("   Item #") .Append(id) .Append(" ") .Append(name) .Append(" ") .Append(qty);

return sb.ToString; }

} }

code



6.1 Test 2
The Client Application code is shown below: code format="csharp" public class Client {       private string name; private Address address; private string notes;

public Client {       }

public string Name {           get { return name; } set { name = value; } }

public Address Address {           get { return address; } set { address = value; } }

public string Notes {           get { return notes; } set { notes = value; } }

public void SetAddress(Address address) {           this.address = address; }

public override string ToString {           StringBuilder sb = new StringBuilder;

sb.Append(name) .Append(", ") .Append(address.ToString) .Append("\nNotes: ") .Append(notes);

return sb.ToString; }   }

code This test involves setting values for each of the variables in the class than after that run a string comparison to see if the ToString method is outputting the right value. Below is the Nunit test class that’s setting those values and comparing them to my values using the StringAssert method:

code format="csharp" [Test] public void ClientToStringTest {           _address = new Address;

_address.City = "Orlando"; _address.Country = "USA";

_Client = new Client; _Client.Name = _name; _Client.Address = _address; _Client.Notes = _notes;

StringBuilder sb = new StringBuilder; sb.Append(_name) .Append(", ") .Append(_address.ToString) .Append("\nNotes: ") .Append(_notes); _expectedResult =sb.ToString;

StringAssert.AreEqualIgnoringCase(_expectedResult,_Client.ToString); }

code The test is successfully run shown by the screenshot below.



6.2 Test 3
Thist test is to show that the Client class will throw an exception if one of the variables is set to a null value. I set the _name variable to null, then ran the .ToString method to see if it would throw the Null exception. The NUnit test is written to expect a null reference exception. The test is successful if the null exception is thrown. The code below is from the Nunit test class and it’s testing for the capability of the client class to handle null exception so that it won’t take in wrong results. code format="csharp" [Test] [ExpectedException(typeof(NullReferenceException))] public void NullReferenceTest {           //_address= new Address; _Client = new Client; _Client.Name = _name; _Client.Address = _address; _Client.Notes = _notes; _name = null;

StringBuilder sb = new StringBuilder; sb.Append(_name) .Append(", ") .Append(_address.ToString) .Append("\nNotes: ") .Append(_notes); _expectedResult = sb.ToString; }

code The result of the test was successful and is shown in the image below, the null exception flag is thrown.



6.3 Test 4
The last test is to check the Address class ToString method since the Client class is dependent of it giving the right values. Just like the test before, I use the StringAssert to compare the expected result to the actual value from the Address class ToString Method. The code below is from the Nunit test class and it does the comparing of the values.

code format="csharp" [Test] public void AddressToStringTest {          _address = new Address; _address.City = "Orlando"; _address.Country= "USA"; StringBuilder sb = new StringBuilder; sb.Append(_city) .Append(", ") .Append(_country);

_expectedResult = sb.ToString; StringAssert.AreEqualIgnoringCase(_expectedResult, _address.ToString); }

code The result of the test is successful and is shown below: