Skip Navigation LinksHome > View Post

Automatically Unit Test your Model

UPDATE: This library has now been significantly updated and moved to codeplex: details here.

I've been sleeping on this idea for a while now having put all the code together about 2 years ago. The idea is pretty simple - a way to easily test your domain classes. You know, the plain old data shapes that look something like this:

public class Person
{
    private string _name;

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

    private DateTime _dateOfBirth;

    public DateTime DateOfBirth
    {
        get { return _dateOfBirth; }
        set { _dateOfBirth = value; }
    }

    // etc..
}

Stuff that nobody ever tests directly because it would be so time consuming. I found this very annoying because of the loss of code coverage in my test suite and then disaster struck. I made a change to such code that accidentally broke one of the properties (two different public getters returned the same private string).

Something had to be done and the ClassTester was born.

What it can do:

  • Automatically test properties, spotting any miswired getters or setters
  • Increase code coverage, reaching parts manual tests don't even try to
  • Supports ignoring specified properties if you have any funky logic in there that needs a manual test
  • Tests for PropertyChanged events if your class implements INotifyPropertyChanged
  • Tests constructors and that they map parameters to properties
A ClassTesterException is thrown by the ClassTester when a problem is found which should cause your tests to fail.

How it works

The ClassTester simply uses reflection to discover the subject's properties. Random values are then injected via the property setters and the getter is invoked and the ClassTester verifies that we get the same value back. Here we test our Person class above:

[TestMethod]
public void TestPerson()
{
    ClassTester tester = new ClassTester(new Person());
    tester.TestProperties();
}

If the ClassTester fails and throws a ClassTesterException then the test fails. Perfick!

The ClassTester is reasonably type aware but will skip properties with non default types (such as interfaces). It is important to utilise this test in conjunction with a code coverage tool to ensure the bits you think are being tested actually are!!.

Some properties just can't be tested in this way, either because they perform some funky logic that is dependant on other state in the class or because they don't return the same value that was set. Like this nonsensical example below that we'll add to our person class:

private int _nonsensicalProperty;

public DateTime NonsensicalProperty
{
    get { return 0; }
    set { _nonsensicalProperty = value; }
}

No problem, we can still use the tester by specifying that this property should be ignored.

[TestMethod]
public void TestPerson()
{
    ClassTester tester = new ClassTester(new Person());
    tester.IgnoredProperties.Add("NonsensicalProperty");
    tester.TestProperties();
}

INotifyPropertyChanged support

This is perhaps the most compelling use of the tester given how easy it is to mess up firing the INotifyPropertyChanged due to the lack of compile time support (it's based on strings).

public class Person : INotifyPropertyChanged
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }

    // etc..

In fact, this is the exact reason I dug this old tool out. As you've probably noticed I've been doing a fair bit of WPF lately. And I'm doing lots of databinding and making lots of use of INotifyPropertyChanged (either directly or via a DependencyObject).

Again, if a specific property doesn't support INotifyPropertyChanged for some reason, then just add it to the ignored list and test it manually.

Download

If you fancy giving this a go you can download the binary: Or you can get the full source with unit tests (NUnit): Please note that this was written in a short time for a personal project and as such hasn't been subject to a great deal of testing. It should be considered SAMPLE CODE. The content is provided "as is" without warranty of any kind, either expressed or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.

Be sure to let me know if you find any bugs or have any feedback by leaving a comment.

This is already a long post so I'll post about support for testing constructors in more detail later.

UPDATE: There's a second post up now describing the constructor testing feature: Testing Constructors with the ClassTester.

UPDATE: This library has now been significantly updated and moved to codeplex: details here.

Tags: .NET

 
Josh Post By Josh Twist
4:43 AM
03 Aug 2007

» Next Post: Testing Constructors with the ClassTester
« Previous Post: Building Chairs out of Atoms

Comments are closed for this post.

Posted by Haacked @ 03 Aug 2007 7:50 AM
Clever! This is perfect for the obsessive compulsive anal types like me. I've always advocated focusing your tests on the parts that are most likely to break, so I would say that testing simple property getters/setters is a waste of time.

But on the flip side, I love seeing that code coverage number go up. Making it trivially easy to test all simple properties is a great compromise.

Posted by Jesse Houwing @ 03 Aug 2007 11:44 AM
Looks great.

There would be a few interfaces I'd like so see in there as well, as they're always hard to get right and most people don't know the exact rules to test these...
- IComparable (would probably need a sorted array of objects to test)
- ISerializable
- Equals/Hashcode contract
- IClonable
- IDisposable

Posted by Rater @ 03 Aug 2007 3:50 PM
Great job. This is such a great idea and so simple.

Posted by Simon @ 03 Aug 2007 5:38 PM
Have you considered putting this up on codeplex?

Posted by Josh @ 04 Aug 2007 2:51 AM
@Simon, now there's definitely some interest I think moving this to codeplex is a good idea (especially when the community already has feature requests, thanks Rater!). I'll look into this soon.

Josh

Posted by Ali Raza Shaikh @ 04 Aug 2007 5:32 AM
I think putting it on CodePlex is a good idea, this is indeed a good thing that will help lot of testers/developers to Unit Test their clasees in less time

Posted by Prakash @ 04 Aug 2007 10:31 PM
nice tool.

Posted by Simon @ 06 Aug 2007 1:08 AM
Can change of constructor parameter being compared to properties?
For example if the constructor is of the form
Person(string lastName, string firstName)
Your class tester could validate that after construction the properties “LastName” and “FirstName” would be checked to see if they match the constructor parameters.
I guess you would need to have some kind of enum to that defines the supported param to property conversions. Something like this perhaps?

public enum ParamToPropertyMapping
{
CamelCase,
CamelCaseUnderscore,
CamelCasePPrefix,
PascalCase,
PascalCaseUnderscore,
PascalCasePPrefix,
}

Posted by Simon @ 06 Aug 2007 1:10 AM
Forget my post.
Just read the followup.
:)

Posted by FTorres @ 06 Aug 2007 7:41 PM
Interesting how some people are trying to write unit tests differently than the xUnit way.

I created QuickUnit.net, it is different from your idea, but it is in the same word.

www.QuickUnit.net, feedback welcome.

Posted by DotNetGuts @ 06 Aug 2007 9:43 PM
Nice article

DNG
http://dotnetguts.blogspot.com

Posted by Bil Simser @ 07 Aug 2007 6:20 AM
Please put this up on CodePlex so we can contribute to the project. I think it's a great idea and can really grow from people in the community who are looking for more. Thanks for a great resource!

Posted by Reflex @ 08 Aug 2007 7:29 AM
It is a idea that also requires a huge amount of time during development. I have been working only on development IT projects where I frequently come accross the limited time factor. There is not enough room for even documenting java documentation on the code. This will be a real overhead for the developers to put their thoughts.


If the framework/design will get some automated code generators for testing then this will be the most welcomed approach with minimal configuration effort.

This is a great idea. I will also be happy to help you out in the design.

Posted by Ricky Clarkson @ 08 Aug 2007 8:09 AM
I'm no C# programmer, but I've checked some details with ##csharp on Freenode IRC..

It seems that the problem you have is that you can't declare _name within public string Name { here }. If you could do that, it would be inaccessible from any other property.

One solution would be to create a Property class that holds the value, and exposes get and set methods, so you get: person.name.set("Phil"), which is not as good as person.name="Phil". You could make Property expose a property called value, so you get: person.name.value="Phil", and if C# had VB.NET's default properties, you could make value the default property, so then you'd be back to person.name="Phil".

That said, I would expect it to be easy to write a source analyser that would find the bugs that you mention. I expect such a thing already exists, perhaps in ReSharper.

Posted by Josh Twist @ 10 Aug 2007 3:37 AM
To be honest, like haacked points out, this isn't just about finding bugs. It's also about pushing up the code coverage number.

And this isn't as anal as it sounds. If you're aiming for a high number, missing all this valid code can make it easier to miss code with a higher chance of containing a bug. It's practically free (with this tool) so why not do it.

Posted by jon @ 01 Nov 2007 11:08 AM
is there any license associated with the source? we're looking at modifying and extending this code to make it even more useful for our testing environment. we'd be more than happy to share the changes :).

Posted by Josh @ 01 Nov 2007 2:43 PM
This is actually on codeplex right now at http://www.codeplex.com/classtester under the Microsoft Permissive License (Ms-PL).

Be sure to check out the latest source as it has changed a fair bit.

Once this project comes out of its current inertia (mostly due to the contributors being too busy elsewhere right now) this will be spit n' polished up and I'll have a post here that announces its completion. But until then...

Posted by prasanna @ 05 Feb 2009 11:47 PM
too good
& supporting more for freshers in this topic

© 2005 - 2014 Josh Twist - All Rights Reserved.