Extension: ToPrintableString() dynamically print an object and its properties

Have you ever wanted to print out an object and all its property values to a log file or an error message? Have you overridden the ToString() method on all your objects to do this? If you have, you know how tedious it can be, and you will really appreciate this method.

What does it do?

Given:

obj = new TestClass();
obj.Value1 = "abc";
obj.Value2 = "123";

Callling:

obj.ToPrintableString();

Yeilds a string containing:

{{ TestClass { Value1 = [ abc ]; Value2 = [ 123 ]; } }}

This is all generated dynamically with reflection. It will print out any properties with public getters.

The Code

The ToPrintableString() method does most of the work.

public static class ObjectExtensions
{
    public static string ToPrintableString< T >this T objectToPrint ) where T : class
    {
        Type type = typeof ( T );

        var sb = new StringBuilder();
        sb.AppendFormat"{{{{ {0} {{ "type.Name );

        foreach ( PropertyInfo property in type.GetPublicGetProperties() )
        {
            sb.AppendFormat"{0} = [ {1} ]; ",
                             property.Name,
                             property.GetValueobjectToPrintnull ) );
        }

        sb.Append"} }}" );

        return sb.ToString();
    }
}

The GetPublicGetProperties() gets the properties with public getters. This method is part of my ReflectionExtensions class. I include it here for completeness.

public static class ReflectionExtensions
{
    public static PropertyInfo[] GetPublicGetPropertiesthis Type type )
    {
        return type.FindMembersMemberTypes.Property,
                                 BindingFlags.Public | BindingFlags.Instance,
                                 ( mf ) => ( (PropertyInfo)m ).CanRead,
                                 null )
                            .Cast< PropertyInfo >()
                            .ToArray();
    }
}

This code can be found in my Shiloh.Testing github repository.

Enjoy!

-Chris

Posted in .NET, C# | Tagged , | Leave a comment

A Dynamic Equality Assertion Method in C#

Ever wanted to assert two objects were equal without having to manually compare their public properties one at a time? Now you can. This method asserts the equality of any two objects by comparing the values of all public, readable properties that have matching names and types. It will compare them even if the objects are different types. This may very well be the last object assertion method you will ever need!

Usage

First let’s look at how we would use the method by looking at the tests. The method is called should_be_equal_to().

public class TestClass1
{
	public int Value1 { get; set; }
	internal int Value2 { get; set; }
}

public class TestClass2
{
	public int Value1 { get; set; }
}

[ TestFixture ]
public class GlobalEqualityAssertionTests
{
	[ Test ]
	public void comparing_two_identical_instances_of_the_same_class_should_pass()
	{
		var obj1 = new TestClass1 {Value1 = 1};
		var obj2 = new TestClass1 {Value1 = 1};
		obj1.should_be_equal_to( obj2 );
	}

	[ Test ]
	public void comparing_two_instances_of_different_classes_that_have_the_same_public_property_where_both_instances_have_the_same_value_for_that_property()
	{
		var obj1 = new TestClass1 {Value1 = 1};
		var obj2 = new TestClass2 {Value1 = 1};
		obj1.should_be_equal_to( obj2 );
	}

	[ Test ]
	public void comparing_two_instances_of_different_classes_that_have_the_same_public_property_where_the_values_for_that_property_differ()
	{
		var obj1 = new TestClass1 {Value1 = 1};
		var obj2 = new TestClass2 {Value1 = 2};
		Assert.Throws< AssertionException >( () => obj1.should_be_equal_to( obj2 ) );
	}

	[ Test ]
	public void comparing_two_instances_of_the_same_class_where_an_internal_property_differs_should_pass()
	{
		var obj1 = new TestClass1 {Value1 = 1, Value2 = 1};
		var obj2 = new TestClass1 {Value1 = 1, Value2 = 3};
		obj1.should_be_equal_to( obj2 );
	}

	[ Test ]
	public void comparing_two_instances_of_the_same_class_with_different_values_should_fail()
	{
		var obj1 = new TestClass1 {Value1 = 1};
		var obj2 = new TestClass1 {Value1 = 2};
		Assert.Throws< AssertionException >( () => obj1.should_be_equal_to( obj2 ) );
	}
}

The Code

Here is the main part of the method…

public static void should_be_equal_to< TActual, TExpected >( this TActual actual, TExpected expected )
{
	foreach ( PropertyPair propertyPair in GetPropertiesToCompare( actual, expected ) )
	{
		object actualValue = propertyPair.Actual.GetValue( actual, null );
		object expectedValue = propertyPair.Expected.GetValue( expected, null );

		Assert.That( actualValue, Is.EqualTo( expectedValue ),
			string.Format( "Expected {0} to match, but did not.", propertyPair.Expected.Name ) );
	}
}

This code loops over all the PropertyPairs we want to compare and compares them. If any value does not match it will fail the assertion with a meaningful error message.

The PropertyPair class is implemented as a private inner class within the assertion class.

private class PropertyPair
{
	public PropertyInfo Expected { get; set; }
	public PropertyInfo Actual { get; set; }
}

Lets look at the code that creates these pairs.

private static IEnumerable< PropertyPair > GetPropertiesToCompare< TActual, TExpected >( TActual actual, TExpected expected )
{
	return
		from exp in GetComparableProperties( expected )
		join act in GetComparableProperties( actual )
				on new {exp.Name, exp.PropertyType}
				equals new {act.Name, act.PropertyType}
		select new PropertyPair {Actual = act, Expected = exp};
}

private static IEnumerable< PropertyInfo > GetComparableProperties< T >( T actual )
{
	return GetPublicGetProperties( actual )
					.Where( property =>
							!property.PropertyType.IsClass &&
							!property.PropertyType.IsInterface
					);
}

private static IEnumerable< PropertyInfo > GetPublicGetProperties< T >( T obj )
{
	Type type = obj.GetType();

	return type.FindMembers( MemberTypes.Property,
					 BindingFlags.Public | BindingFlags.Instance,
					 ( m, f ) => ( (PropertyInfo)m ).CanRead,
					 null )
					.Cast< PropertyInfo >();
}

GetPropertiesToCompare() simply gets the comparable properties for each object type and joins them on name and type. Any properties that don’t match on name and type are ignored. Those that do match are put into a PropertyPair object to be returned.

GetComparableProperties() calls GetPublicGetProperties() to get a list of public readable properties. It then throws out any reference type properties so that only value properties are left. These are the properties that get compared.

Caveats

Note that reference properties (properties that refer to other objects) are not compared, so even if they differ, the objects will show as equal. I have deferred this task since I still need consider how to handle references we don’t want to compare (and there are many).

Where Can I Get It?

This code can be found on my Shiloh.Testing github repository. The link goes to the v0.1 tag, which only has this class and its supporting classes and tests. It includes several other features that I stripped out to make this blog post simpler, like the ability to clean up values before comparing them, and an attribute you can place on properties you want to ignore when asserting equality.

I hope this simplifies your testing…it has definitely simplified mine.

-Chris

Posted in .NET, C#, Testing | Tagged , , | 4 Responses

Slides and Audio for my Introduction to MongoDB presentation

I presented at the Austin .NET User Group this week. The topic was an “Introduction to MongoDB”. Below are the slides and the audio from the presentation.

The talk covers MongoDB from the perspective of a newcomer to the technology. I relate the concepts in MongoDB to their corresponding SQL idioms–pointing out their differences and likenesses. The talk covers much of the functionality and capabilities of MongoDB, from the simple to the complex (queries, indexes, sharding, replication, installation, etc.). A lot of questions that are asked push deeper into the internals, many of which I answer, but several I defer with a simple “I don’t know”.

The talk went much longer than I expected–over 2 hours. I was told it was the longest meeting they ever had. I was pleased at how engaged everyone was. There were so many questions, and many people seemed genuinely interested. I thoroughly enjoyed giving the talk. Can’t wait to do it again!

Resources:

Posted in .NET, MongoDB, NoSQL, Presentations | Tagged , , , | Leave a comment

I will be presenting on MongoDB at the Austin .NET Users Group Monday

Here is the info that will be going out in the ADNUG notice.

Topic: Introduction to MongoDB
The relational database has been around for a very long time. It is used in almost every kind of application imaginable. Most all developers have experience using an RDBMS and use it on almost every project by default. When was the last time you considered using an alternative? You haven’t? Let me invite you to take a step outside the box for a moment.

MongoDB is one of the new breed of “NoSQL” databases available as alternatives to relational databases. It is a document database that represents its data as JSON, and thus requires no schema. It can easily scale across many computers using auto-sharding and supports redundancy for each shard. Come get an overview this database, its scalability and redundancy features, and how to access it via C#. While MongoDB is not meant to replace all SQL databases, its good to know there is an alternative for the cases where it is the better fit.

Speaker: Chris Edwards
Chris Edwards is a senior software developer with BancVue, Ltd. based in Austin, TX. He has over 15 years of professional software development experience in a diverse set of environments and technologies, but has mostly focused on the Microsoft stack. Chris decided at a young age to pursue software development after seeing the movie WarGames, and has never looked back since. Now 26+ years later he is still writing code with the same passion. Chris has presented as several of the Austin Code Camps, and actively promotes and contributes to open source software. When not coding, he can be found spending time with his family or serving at Hill Country Bible Church, Hutto. He blogs at http://chrisedwards.dreamhosters.com/ and you can find some of his work on http://github.com/chrisedwards/

Monday November 8th 5:30-8:00pm

***New Location***
Microsoft Technology Center: Austin
Quarry Oaks II
10900 Stonelake Blvd., Suite 225
Austin, TX 78759
(512) 795-5300

Posted in .NET, MongoDB, Presentations | 3 Responses

Creating a new gemspec for the Nubular Project (Nu) is easier than you might think

I just started using Nu to manage the dependencies in my Fluency project. I had used package managers for ruby and php in the past, and loved them, so I couldn’t pass up the opportunity to try out Nu. I am glad I did.

What the heck is Nu?

Nu is a package manager for .NET (finally!). It allows you to install code libraries and all their dependencies automatically, and keep them updated. If you have ever heard of RubyGems, this is the same thing. In fact, its built on top of ruby gems!

Installing Nu

To use Nu, you first need to install ruby. You can get it here. Then upgrade RubyGems by dropping to a command prompt and typing

gem update --system

Then to install Nu you type

gem install nu

And that’s it…Nu is installed and ready to go.

Using Nu

Using Nu is dirt simple. Wanna install NUnit?

C:\project>nu install nunit
Gem nunit is not installed locally - I am now going to try and install it
Successfully installed nunit-2.5.7.10213.20100801
Installed package nunit.

Done! How about NHibernate?

C:\project>nu install nhibernate
Gem nhibernate is not installed locally - I am now going to try and install it
Successfully installed nhibernate-2.1.2.4000
Loading dependency: castle.core = 1.1.0.0
Loading dependency: castle.dynamicproxy2 = 2.1.0.0
Loading dependency: castle.core = 1.1.0.0
Loading dependency: log4net = 1.2.10.0
Installed package nhibernate.

Sure beats the pants off navigating out to the website to download the latest version, doesn’t it? And it even installed all the dependencies.

image

Creating a gem to be installed using Nu

So what does it take to make a project installable using Nu? Not much. I was surprised at how easy it was.

When I converted Fluency to install all its dependencies using Nu, I found one library that that wasn’t yet packaged as a gem and installable through Nu. This was the SharpTestsEx library. So I did what any self-respecting supporter of open-source software would do, I decided to add it myself so anyone else could use it.

1. Prepare the gemspec

To do this, I created a gems folder and in it, a gemspec file “sharptestsex.gemspec” with the following contents

version = File.read(File.expand_path("../VERSION",__FILE__)).strip

Gem::Specification.new do |spec|
  spec.platform    = Gem::Platform::RUBY
  spec.name        = 'sharptestsex'
  spec.version     = version
  spec.files = Dir['lib/**/*']
  
  spec.summary     = 'Sharp Tests Ex - .NET Fluent Assertions for Your Tests'
  spec.description = '#TestsEx (Sharp Tests Extensions) is a set of extensible extensions. The main target is write short assertions where the Visual Studio IDE intellisense is your guide. #TestsEx can be used with NUnit, MsTests, xUnit, MbUnit.'
  
  spec.authors           = ['Fabio Maulo','JDiamond']
  spec.email             = ''
  spec.homepage          = 'http://sharptestex.codeplex.com/'
  spec.rubyforge_project = 'sharptestsex'
end

and a “VERSION” file that simply contained the version number

1.0.0.0

I then created a gems/lib/ folder and placed the binaries in it. The spec.files attribute indicates that I want to include all the files in this folder in the gem.

2. Build and test the gem locally.

Then I built the gem at the command prompt with

gem build sharptestsex.gemspec

This will product the gem file names sharptestsex-1.0.0.0.gem. I tested it with nu locally by installing the gem directly (without going to the rubygems server) by specifying the filename of the gem.

gem install sharptestsex-1.0.0.0.gem

This installed it from my local drive into the gem cache. The gem cache is where nu gets the libraries. If nu does not find the requested library in the gemcache, it asks rubygems to get it from the server. Installing it like I did above ensured its in the cache so nu could find it. Then I tested that nu could install it.

nu install sharptestsex

Once I saw it all worked, I uninstalled the gem so that I would be able to test that it pulls from the server. Uninstalling the gem deletes it from the local gemcache. I had to do this because if it existed in the cache, it wouldn’t even try to download if from the server the next time I test it. I uninstalled it with…

gem uninstall sharptestsex

3. Push the gem to RubyGems.org

Now I was ready to push the gem out to RubyGems.org. To do that, I needed to sign up for a free account, which was quick and painless. The I pushed the gem up.

gem push sharptestsex-1.0.0.0.gem

I was prompted for my RubyGems.org login and password, and then the gem was uploaded. 

4. The final test

Then my new gem is ready to install with nu! I tested it with…

nu install sharptestsex

I checked, and sure enough, I saw a lib folder that contains a sharptestsex folder with all the binaries. It was way easier than I thought.

Resources

I drew heavily from the following resources while getting this to work.

Posted in .NET, C# | Tagged , | Leave a comment