Lets say you want to do some TDD, as you may know that you have in some/most test an Expected answer and an Actual answer. In the case of the expected/actual being a value type or string its easy just to use:

Assert.AreEqual<string> ("this is expected", Actual, "the string values did not match");

 However in the case where these varibles are business objects, you will need to override the "==" and/or the Equals operators. Thats perfect when all you business objects have this implemented, but what can you do when they don't. One thing that comes to mind is either going and adding overrided methods in all your object, or you could add an assert for every property in the class. Well I was a little bit lazy/curious to see if I could use reflection, and this is what I came up with:

public static bool isEqual(object Actual, object Expected)
{
    if (Actual.GetType() != Expected.GetType())
    {
        throw new ArgumentException
            ("both inputs have to be of the same type");
    }
    Type t = Actual.GetType();
    PropertyInfo[] ps = t.GetProperties();
    foreach (PropertyInfo p in ps)
    {
        //only test the value types and strings
        if ((p.PropertyType.IsValueType) ||
            (p.PropertyType == typeof(string)))
        {


            List<Type> paramTypes = new List<Type>();
            string PropertyName = p.Name;
            //not needed as they should not have parameters
            //foreach (ParameterInfo param in p.GetIndexParameters())
            //{
            //    paramTypes.Add(param.ParameterType);
            //}

            //get the first value
            object val1 = t.GetProperty(PropertyName,
                paramTypes.ToArray()).GetValue(Actual, null);
            //get the second value
            object val2 = t.GetProperty(PropertyName,
                paramTypes.ToArray()).GetValue(Expected, null);
            //make sure they are the same
            if (!val1.ToString().Equals(val2.ToString()))
            {
                return false;
            }
        }
    }
    return true;
}

The above uses reflection to test all the value type and string properties in the object to see if they are the same. This will take in 2 objects of the same type and return true if they contain the same values (a little like the assert.AreEqual<youObject>).

Take the following example:

static void Main(string[] args)
{

    person p1 = new person();
    person p2 = new person();
    person p3 = new person();
    person p4 = p1;

    p1.Name = "dave";
    p1.Age = 25;

    p2.Name = "dave";
    p2.Age = 25;

    p3.Age = 23;
    p3.Name = "troy";

    Console.WriteLine(string.Format("p1 = p2 : {0}", p1 == p2));
    Console.WriteLine(string.Format("p1 = p4 : {0}", p1 == p4));
    Console.WriteLine(string.Format("isEqual(p1, p2) : {0}", isEqual(p1, p2)));
    Console.WriteLine(string.Format("isEqual(p3, p2) : {0}", isEqual(p3, p2)));
    Console.ReadLine();
}

note the isEqual(p1, p2) is true, which is awesome for some cases of unit testing. (consider the saving and loading of an object to and from a DB, testing to see if it returned the same object)

 finally the code for the person class: (as you can see its a simple class)

class person
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    private int _age;
    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }
}

but if you would like to know how to override the "==" and Equals take a look at this MSDN article:

http://msdn2.microsoft.com/en-us/library/ms173147.aspx

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Method Overloading with Inheritance

Published 2/5/2008 by Dave in dotNet
Tags:

Here is a fun one.... read the following, and guess the output

class Program
{
    static void Main(string[] args)
    {
        b test2 = new b();
        a test1 = test2;
        //guess the output
        print(test1);
        print(test2);

        Console.ReadLine();
    }


    public static void print(b p1)
    {
        Console.WriteLine(string.Format("{0}, {1}, {2}", p1.Name, p1.age.ToString(), p1.GetType().ToString()));
    }

    public static void print(a p1)
    {
        Console.WriteLine(p1.Name + " " + p1.GetType().ToString() );
    }  
}

class a
{
    public string Name = "dave";
}

class b : a
{
    public int age = 25;

    public b()
    {
        this.Name = "Dave 2";
    }
}

come on guess it, before you run it! :)

 

 

Ok here is the output: (it was not what i expect or wanted)

 

Note that the first print, for test1, uses print(a) (which i do not agree with), and has a type of b (which I do agree with). This would suggest that the method overload is mapped at compile time. Sofar the only work around i have found is to create a new static class called p and move the print methods into this, now you can use reflection to call the right method depending on its runtime type:

//in the main method
p proc = new p();

MethodInfo mi= proc.GetType().GetMethod("print", new Type[] {t});

mi.Invoke(null, new object[] { test1 });

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

A Text file test trace listener

Published 2/4/2008 by Dave in dotNet | Test
Tags:

Testing your logging functionality, using the Enterprise library and a custom trace listener. As I was in need of a method to test some loggin functions, i googled away and found this exellent article

<http://blogs.msdn.com/ploeh/archive/2006/04/06/
UnitTestYourEnterpriseLibraryLoggingLogic.aspx
> by ploeh.

I have slightly modified this code to use a text file, allowing me to view the test data in a text file and read it back in. Here is my alterations (consider this a small tribute to a great article.)

 In the rest of this article i will go through the differences

the Write and WriteLine methods output the the textfile

/// <summary>
/// Overriden write menthod, this will write directly to
/// the log
/// </summary>
/// <param name="message"></param>
public override void Write(string message)
{
    StreamWriter sw = null;
    try
    {
        sw = new StreamWriter(CreateLog());
        sw.Write(message);
    }
    catch (Exception ex)
    {
       throw new Exception("cannot write to file :", ex);
    }
    finally
    {
        if (sw != null)
            sw.Close();
    }
   
}

/// <summary>
/// Write line
/// </summary>
/// <param name="message"></param>
public override void WriteLine(string message)
{
    StreamWriter sw = null;
    try
    {
        sw = new StreamWriter(CreateLog());
        sw.WriteLine(message);
        sw.WriteLine("<--End-->");
        sw.WriteLine("");
    }
    catch (Exception ex)
    {
        throw new Exception("cannot writeline to file :", ex);
    }
    finally
    {
        if (sw != null)
            sw.Close();
    }
}

The overriden TraceData method remins similar just removed the addtion to the collection

public override void TraceData(TraceEventCache eventCache,
    string source, TraceEventType eventType, int id,
    object data)
{
    LogEntry le = data as LogEntry;
    if (le != null)
    {
        if (Formatter != null)
        {
           
            WriteLine(Formatter.Format(le));
            return;
        }
    }
    base.TraceData(eventCache, source, eventType, id, data);
}

 now when you add this to your Logging as a listner it will produce a log which will look similar to this

[code]

Timestamp: 04/02/2008 15:58:04
Message: 3ef9ed0b-33a2-4701-8b98-c76b4ace8ae0
Category: General
Priority: 1
EventId: 123
Severity: Critical
Title:unit test 04/02/2008 15:58:04
Machine: machineName
Application Domain: UnitTestAdapterDomain_ForD:\TestLogging.dll
Process Id: 2296
Process Name: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\vstesthost.exe
Win32 Thread Id: 344
Thread Name: AdpaterExeMgrThread1
Extended Properties:
<--End-->

Timestamp: 04/02/2008 19:04:34
Message: 33beaba7-4d21-4d55-a7ac-629877cdaac0
Category: General
Priority: 1
EventId: 123
Severity: Critical
Title:unit test 04/02/2008 19:04:33
Machine: machineName
Application Domain: UnitTestAdapterDomain_ForD:\TestLogging.dll
Process Id: 4276
Process Name: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\vstesthost.exe
Win32 Thread Id: 5940
Thread Name: AdpaterExeMgrThread1
Extended Properties:
<--End-->

 So Now we need a function or two to get the results back as log objects, allowing us to write unit tests against the results. Using regular expressions, we can get all the information quite simply :

[code]

((?:Timestamp\:)(?<Timestamp> .*))
((?:Message\:)(?<Message>(.|[\n\r])*?))
((?:Category\:)(?<Category> .*))
((?:Priority\:)(?<Priority> .*))
((?:EventId\:)(?<EventId> .*))
((?:Severity\:)(?<Severity> .*))
((?:Title\:)(?<Title>.*))
((?:Machine\:)(?<Machine> .*))
((?:Application Domain\:)(?<ApplicationDomain> .*))
((?:Process Id\:)(?<ProcessId> .*))
((?:Process Name\:)(?<ProcessName> .*))
((?:Win32 Thread Id\:)(?<Win32ThreadId> .*))
((?:Thread Name\:)(?<ThreadName> .*))
((?:Extended Properties\:)(?<ExtendedProperties>(.|[\n\r])*?))

This regex will work for the default formatter which the Patterns and Practices uses. As you may have noticed it uses groups, allowing for us to easily reference the values in a method to retrive. The following takes the above regex and populates the values into LogEntry objects

/// <summary>
/// load all the log into an array
/// </summary>
/// <param name="fileLocation"></param>
/// <returns></returns>
public static List<LogEntry> GetAllLogEntries()
{
    Regex reg = new Regex(logRegEx, RegexOptions.Multiline);
    string log = File.ReadAllText(LogLocation);
    List<LogEntry> result = new List<LogEntry>();
    MatchCollection mC = reg.Matches(log);

    LogEntry l;
    Console.WriteLine("loading data");
    foreach (Match m in mC)
    {
        l = new LogEntry();
        l.Message = m.Groups["Message"].ToString().Trim();
        l.TimeStamp = DateTime.Parse(m.Groups["Timestamp"].ToString().Trim());
        l.Priority = int.Parse(m.Groups["Priority"].ToString().Trim());
        l.Title = m.Groups["Title"].ToString().Trim();
        result.Add(l);
    }

    Console.WriteLine("loaded " + result.Count.ToString() + "logs entries");

    return result;
}

Its simple to use, I placed this in a Class library built it and then referenced it from the logger and from my unit tests.

TextTraceListener.cs (6.34 kb)

Todo:

add this into a class library project. (give it the name :LoggingLibraryTest)
Compile the project (this will generate a DLL file.)

reference the DLL with in your TDD ptoject, and also set the Enterprise logging to custom and point the custom listner to a copy of the DLL.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

You may have noticed I have the code on this blog highlighted, well i was looking into a way to highlight the classes as it does in visual studio 2005. As im restricted on the level of reflection i can actually do within the website. My next idea is can i create a list of the common classes I use. so here is a quick (i mean quick) moke up of my thoughts and code

I wanted to list common classes, for example classes found in

System.Data
System.Xml
System.Configuration
System.Windows
System.Web

this should cover most example code placed on this site (well its good enough for now :P )

//declare all the required vars
List<string> classes = new List<string>();

//use a single type to get the assembly
//save me from writing the location and name of each
//assembly
Type[] ts = new Type[] {
 typeof(DataSet), 
     typeof(XmlDocument),
     typeof(ConfigurationManager), 
     typeof(System.Windows.Forms.DataGridView), 
     typeof(System.Web.HttpCookie) };

foreach (Type t in ts)
{
     //get the types in each assembly
     Assembly a = Assembly.GetAssembly(t);
     //add the list of classes to the main list
     classes.AddRange(GetTypes(a));
}

The above will use the types, one from each of the namespaces I wanted to get the classes from. Then it loads the assembly and calls the GetTypes function.

Below is the Get types function, this will list all the Public classes contained in each of the Assemblies.

public static List<string> GetTypes(Assembly main)
{
    List<string> result = new List<string>();
    string tName;
    bool ok;

    Type[] types = main.GetTypes();
    foreach (Type t in types)
    {
        tName = t.Name;
        //do not include classes with these symbols, safe to say their are not
        //every day use. (could of used regex)
        ok = (!tName.Contains("_") && !tName.Contains( "<") && !tName.Contains("$"));
       
        //do not add a class name if
        //it has a symbol
        //we have already listed it
        //its not public.. if we cannot access it, there is no point listing it.
        if (ok && !result.Contains(t.Name) && t.IsPublic)
            result.Add(t.Name);

    }
    return result;
}

and thats it. from there i wrote a foreach, to print all the class names to a text file. I have attached the entire source code. Its simple, and i guess it could have been done a little neater, but it works for me :)

Programcs.rar (1.05 kb) <-  source code

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5