Tuesday 26 July 2011

Unit Testing C# Custom Attributes with NUnit Part 3

During Unit Testing C# Custom Attributes with NUnit Part 2 where the Assertions were converted from the Classic to the Constraint model it was simply a process of replacing

Assert.<SomeAssertion>(<object>)

with

Assert.That(<object>, Is.<SomeAssertion>)

The key thing being the 'Is' object that houses all the original assertions used.  Whilst doing this I came across the 'Has' object.  This doesn't appear in the documentation until about halfway when collections are covered.  Not mentioned at all in the documentation is the method Has.Attribute<AttributeType> which tests whether an attribute (custom or otherwise) is present on the object being tested.   For the current method this is simply:

Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>());

Even better, having obtained the Attribute (if not present the assertion will fail) it too can be tested.  The important aspect here is that it contains a specific property which can easily be tested in the same statement by appending '.Property(<PropertyName>)' in a Fluent style to give:

Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>().Property("FunkyName"));

The next is to test whether this property contains the correct value.  This can be obtained in a similar way by further appending '.EqualTo(<SomeValue>)' to give:

Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>().Property("FunkyName").EqualTo("RipSnorter"));

In a single statement tests for the presence of the Custom Attribute, a property of it and finally that property's value have been conducted.  This is considerably shorter than both the original and second examples which required the reflection code to obtain the Custom Attribute followed by 3 separate assertions.

This does not meet the original testing requirements which were:

  • A Custom Attribute of the correct type existed on the test method.
  • That the property to be tested of the Custom Attribute had the expected name.
  • That the property to be tested of the Custom Attribute had the correct type.
  • That the value of property to be tested of the Custom Attribute could be set.
  • That the value of property to be tested of the Custom Attribute could be obtained.
  • That the property to be tested of the Custom Attribute had the expected value.

Remaining are setting, getting (obtain) and type checking.

It turns out that that the tests for being able to set and get the property are not needed as if a property is created on a Custom Attribute then a getter and setter must be supplied.  The property can be private but if this is the case then it cannot be set as part of the Attribute syntax.  If the former condition is not met or an attempt is made to set a private property then a compilation error will occur.

Whilst successfully testing the property's value would suggest a type match this it not strictly the case as if the expected value can be converted to the type of the property then the test will be successful, e.g.

Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>().Property("SettingOne").EqualTo(77.0));

which causes the double to be converted to an int.  It wouldn't be possible to actually set 'SettingOne' to a double value when using the attribute as this will fail to compile, e.g.

[Funky(SettingOne = 77.9)]

As this is testing an implementation of a Custom Attribute rather than its application then it is necessary to check that the implementation hasn't been accidentally changed to allow this in which case the previous erroneous test would pass.  This means testing the type.

Unfortunately this is where the Fluent interface of NUnit's Constraint model falls downs a little as it's not possible to perform multiple tests on the same initial subject which in this case is the MethodBase returned from the static MethodBase.GetCurrentMethod() call.  Therefore an additional assertion is required:

Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>().Property("SettingOne").TypeOf<int>());

This means the original example can be reduced to the following:

[Test]
//[Funky(FunkyName = "RipSnorter")]
public void TestThatNameIsRipSnorter()
{
 Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>().Property("FunkyName").EqualTo("RipSnorter"));
 Assert.That(MethodBase.GetCurrentMethod(), Has.Attribute<FunkyAttribute>().Property("FunkyName").TypeOf<string>());
}

[Test]
[Funky(SettingOne = 77)]
public void TestThatSettingOneIs77()
{
 // Two asserts
 Assert.That(MethodBase.GetCurrentMethod(), 
             Has.Attribute<FunkyAttribute>().Property("SettingOne").EqualTo(77));
 Assert.That(MethodBase.GetCurrentMethod(), 
             Has.Attribute<FunkyAttribute>().Property("SettingOne").TypeOf<int>());

 // Use of '.And'.  Note the trailing '.'
 Assert.That(MethodBase.GetCurrentMethod(), 
             Has.Attribute<FunkyAttribute>().Property("SettingOne").TypeOf<int>().
             And.Attribute<FunkyAttribute>().Property("SettingOne").EqualTo(77));
// Use of overloaded '&'
 Assert.That(MethodBase.GetCurrentMethod(), 
             Has.Attribute<FunkyAttribute>().Property("SettingOne").TypeOf<int>()
           & Has.Attribute<FunkyAttribute>().Property("SettingOne").EqualTo(77));
}

with the Custom Attribute definition remaining as

public class FunkyAttribute : Attribute
{
 public int SettingOne { get; set; }
 public string FunkyName { get; set; }
}
In the TestSettingOneIs77 method the need for two separate assertions has been slightly improved upon.  This is by using the 'And' method which is of the Fluent style.  The final assertion is exactly the same as the previous but just demonstrates the overloaded '&' syntax instead.  

I don't think either of these styles is particularly better than the two line equivalent as they both require two calls to obtain the Custom Attribute; one for each test.  However, using NUnit's Constraint model coupled with Fluent interface reduces the required code dramatically so is worthwhile.  Additionally I'm not sure if the Classic model actually allows Attributes to be obtained.  

A test per-property on a Custom Attribute is probably also desirable but there's nothing stopping you combining all the individual property tests into a single assertion by the use of  '.And.HasAttribute().Property().EqualTo()'.  One of these would be required  for each of the remaining properties along with a similar one for the type check.  A test per-property is more readable.


I think I'm done for a while on this subject now!

Unit Testing C# Custom Attributes with NUnit Part 2

I thought that my last post about Unit Test C# Custom Attributes with NUnit was going to be the only one.  However, after reading more of the NUnit documentation I found that despite the QuickStart guide using the Classic model the preferred model for working with NUnit is that of Constraints.  As such I thought I ought to change over to this which is what the updated code below shows.

[Test]
[Funky(FunkyName = "RipSnorter")]
public void TestThatNameIsRipSnorter()
{
 TestAttrProperty<FunkyAttribute, string>(MethodBase.GetCurrentMethod(), "FunkyName", "RipSnorter");
}

[Test]
[Funky(SettingOne = 77)]
public void TestThatSettingOneIs77()
{
 TestAttrProperty<FunkyAttribute, int>(MethodBase.GetCurrentMethod(), "SettingOne", 77);
}

// Helpers
private void TestAttrProperty<TAttr, TProp>(MethodBase method, string argName, TProp expectedValue)
{
 object[] customAttributes = method.GetCustomAttributes(typeof(TAttr), false);

 Assert.AreEqual(1, customAttributes.Count());

 TAttr attr = (TAttr)customAttributes[0];

 PropertyInfo propertyInfo = attr.GetType().GetProperty(argName);

 Assert.That(propertyInfo, Is.Not.Null);
 Assert.That(propertyInfo.PropertyType, Is.EqualTo(typeof(TProp)));
 Assert.That(propertyInfo.CanRead, Is.True);
 Assert.That(propertyInfo.CanWrite, Is.True);
 Assert.That(propertyInfo.GetValue(attr, null), Is.EqualTo(expectedValue));
}

The major change is rather that than calling Assert.<Assertion> the Constraint model starts with specifying the object to be tested followed by the test.  Additionally, the Constraint model encourages a Fluent style interface, e.g.

Assert.IsNotNull(propertyInfo);

becomes

Assert.That(propertyInfo, Is.Not.Null);

I'm not going to explain the new model here (the above link has the details) but rather this is to just point out this style which can be contrasted to the sample in the previous post.

In addition I remembered that a far easier way to obtain the current method metadata, i.e. MethodBase was to simply to use reflection by calling MethodBase.GetCurrentMethod() from System.Reflection.

You might also have noticed that in this updated example the FunkyAttribute property Name has become FunkyName.

public class FunkyAttribute : Attribute
{
 public int SettingOne { get; set; }
 public string FunkyName { get; set; }
}

This was to differentiate from the Name property of the PropertyInfo class.

However, this isn't the main reason for part 2.  However, this post seems long enough already so the good bit will come in part 3 which I'll write immediately so not too much waiting around.  A part 4 also emerged!

Wednesday 20 July 2011

Unit Testing C# Custom Attributes with NUnit

I've been experimenting with TDD and as usual I've seemed to pick a non-standard problem to start with.  In this case I was creating a new C# Custom Attribute class, e.g.

public class FunkyAttribute : Attribute
{
 public int SettingOne { get; set; }
 public string Name { get; set; }
}

which would be used such as

[Funky(Name="SomeThingFunkierThanJust_f")]
public static int f() { return 7; }

Testing this is a little strange as rather than having a standard test method which invokes a method and asserts the result, e.g.

Monday 18 July 2011

A Simple WPF ComobBox based Brush Selector Control

Following the last Code Project article I popped my stack and finished the original article that spawned it.  It's up on Code Project now and you can find it here or in long hand: from http://www.codeproject.com/KB/WPF/BrushSelectorArticle.aspx

As the title suggests this one shows how to implement a simple control that allows a SolidColorBrush to be selected from a panel.  In fact it demonstrates how to do with using a Style and a UserControl and compares both approaches.

Tuesday 12 July 2011

Exploring the use of Dependency Properties in WPF User Controls

I recently wrote my first WPF User Control. This was mainly to customize a ComboBox as opposed to implement a completely new control. As such, I needed to access some of the Dependency Properties (DPs) on the ComboBox. Whilst it's possible to dip into the Content property of a UserControl this is somewhat unpleasant as it violates encapsulation. The result was that I spent a bit of time experimenting with different ways to access these DPs whilst retaining the encapsulation of the embedded ComboBox. This is all written up as a Code Project article.

http://www.codeproject.com/KB/WPF/DPsInUserControl.aspx