VB.NET (and C# 4.0) Optional Features – Great for Unit-testing structures and DTO’s!

Here’s a great use-case for Optional parameters in VB.NET (and to be introduced in C# 4.0), it’s saved me lots of code and kept my unit tests small.

Some data structures (DTO’s to some folk, and classes as well) have a large number of properties with the same return type, such as:

public struct MyData
{
public MyData(string firstName, string middleName, string lastName, string surName, string formerName)
{ // set the properties }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string SurName { get; set; }
public string FormerName { get; set; }
// …and so on…
}

Imagine that this strucuture is implemented with field-backed properties (instead of automatically-implemented properties) and we wanted unit tests to ensure that setting SurName didn’t change the backing field for FormerName.  Each unit test would need to instantiate an instance of MyData by passing a laundry-list of parameters.  Here’s a sample of a unit test (and accompanying BuiltTarget() method) showcasing how ugly this can be (notice that BuildTarget() is an ungainly mess; and that there would normally be one or more tests for each parameter).

Public Function BuildTarget(ByVal firstName As String, _
ByVal middleName As String, _
ByVal lastName As String, _
ByVal surName As String, _
ByVal formerName As String) As MyData
Return New MyData(firstName, middleName, lastName, surName, formerName)
End Function

<TestMethod()> _
Public Sub New_WhenFirstNameProvided_KeepsValue()
Dim firstName = “Steve”
Dim target = BuildTarget(firstName, _
Nothing, _
Nothing, _
Nothing, _
Nothing)

Dim expected = firstName
Dim actual = target.FirstName

Assert.AreEqual(expected, actual)

End Sub

To work around this my tests contain a single “BuildTarget()” factory which declares each parameter as optional, and provides a default value.  Then when I need to set just a single parameter I can do so by name and let the default values provide the remaing parameters.  The above sample cleans up to look like:

Public Function BuildTarget(Optional ByVal firstName As String = Nothing, _
Optional ByVal middleName As String = Nothing, _
Optional ByVal lastName As String = Nothing, _
Optional ByVal surName As String = Nothing, _
Optional ByVal formerName As String = Nothing) As MyData
Return New MyData(firstName, middleName, lastName, surName, formerName)
End Function

<TestMethod()> _
Public Sub New_WhenFirstNameProvided_KeepsValue()
Dim firstName = “Steve”
Dim target = BuildTarget(firstName:=firstName)

Dim expected = firstName
Dim actual = target.FirstName

Assert.AreEqual(expected, actual)

End Sub

As you can imaging, the small amount of extra code in the BuildTarget() method is insignificant compareed to the savings in each TestMethod.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: