How to get and set private fields or properties in C#

Sometimes you want to access a private member of an object. If you were the author of such object, you would simply change the encapsulation from private to public, or protected if you just want access from a child. However, what if you don’t have access to the object. What if it is one of the standard .NET library objects. You can’t change it. What are your options?

  1. Rewrite the entire class. (Not easy and I don’t recommend it)
  2. Recreate the value somehow (which might not even be possible)

Well, guess what. Microsoft left a nice workaround to encapsulation in its implementation of Reflection.

Here is a nice class you can use to get the value of any private member.

using System;
using System.Linq;
using System.Reflection;

namespace Rhyous.TextBlock.Business
{
    public class PrivateValueAccessor
    {
        public static BindingFlags Flags = BindingFlags.Instance
                                           | BindingFlags.GetProperty
                                           | BindingFlags.SetProperty
                                           | BindingFlags.GetField
                                           | BindingFlags.SetField
                                           | BindingFlags.NonPublic;

        /// <summary>
        /// A static method to get the PropertyInfo of a private property of any object.
        /// </summary>
        /// <param name="type">The Type that has the private property</param>
        /// <param name="propertyName">The name of the private property</param>
        /// <returns>PropertyInfo object. It has the property name and a useful GetValue() method.</returns>
        public static PropertyInfo GetPrivatePropertyInfo(Type type, string propertyName)
        {
            var props = type.GetProperties(Flags);
            return props.FirstOrDefault(propInfo => propInfo.Name == propertyName);
        }

        /// <summary>
        /// A static method to get the value of a private property of any object.
        /// </summary>
        /// <param name="type">The Type that has the private property</param>
        /// <param name="propertyName">The name of the private property</param>
        /// <param name="o">The instance from which to read the private value.</param>
        /// <returns>The value of the property boxed as an object.</returns>
        public static object GetPrivatePropertyValue(Type type, string propertyName, object o)
        {
            return GetPrivatePropertyInfo(type, propertyName).GetValue(o);
        }

        /// <summary>
        /// A static method to get the FieldInfo of a private field of any object.
        /// </summary>
        /// <param name="type">The Type that has the private field</param>
        /// <param name="fieldName">The name of the private field</param>
        /// <returns>FieldInfo object. It has the field name and a useful GetValue() method.</returns>
        public static FieldInfo GetPrivateFieldInfo(Type type, string fieldName)
        {
            var fields = type.GetFields(Flags);
            return fields.FirstOrDefault(feildInfo => feildInfo.Name == fieldName);
        }

        /// <summary>
        /// A static method to get the FieldInfo of a private field of any object.
        /// </summary>
        /// <param name="type">The Type that has the private field</param>
        /// <param name="fieldName">The name of the private field</param>
        /// <param name="o">The instance from which to read the private value.</param>
        /// <returns>The value of the property boxed as an object.</returns>
        public static object GetPrivateFieldValue(Type type, string fieldName, object o)
        {
            return GetPrivateFieldInfo(type, fieldName).GetValue(o);
        }
    }
}

And here is how to use it.

Imagine you have a class with a private Field and a private property.

public class A
{
    private int MyPrivateProperty
    {
        get { return _MyPrivateField; }
        set { _MyPrivateField = value; }
    } private int _MyPrivateField = 27;
}

You can access the value as follows:

    var a = new A();
    // Get values
    int privateFieldValue = (int)PrivateValueAccessor.GetPrivateFieldValue(typeof(A), "_MyPrivateField", a);
    int privatePropValue = (int)PrivateValueAccessor.GetPrivatePropertyValue(typeof(A), "MyPrivateProperty", a);

    // Set Values
    PrivateValueAccessor.GetPrivateFieldInfo(typeof(A), "_MyPrivateField").SetValue(a, 11);
    PrivateValueAccessor.GetPrivatePropertyInfo(typeof(A), "MyPrivateProperty").SetValue(a, 7);

Access private fields or properties from a base class

OK, so now that we have this class, you can imagine that you can now use it in a child, if you have no other choice, in order to expose A.MyPrivateProp.

public class B : A
{
    public int ExposedProperty
    {
        get { return (int)PrivateValueAccessor.GetPrivateFieldValue(typeof(A), "_MyPrivateField", this); }
        set { PrivateValueAccessor.GetPrivateFieldInfo(typeof(A), "_MyPrivateField").SetValue(this, value); }
    }
}

Now you have exposed the private value in your child class. You can call it as normal.

            var b = new B();
            b.ExposedProperty = 20;

Here is what it looks like in the debugger before you set it.

b    {B}    B
    base    {B}    A {B}
        _MyPrivateField      27    int
        MyPrivateProperty    27    int
        ExposedProperty      27    int
        b.ExposedProperty    27    int

And after setting B.ExposedProperty to 20, it looks like this.

b    {B}    B
    base    {B}    A {B}
        _MyPrivateField      20    int
        MyPrivateProperty    20    int
        ExposedProperty      20    int
        b.ExposedProperty    20    int

Conclusion

You now have a serviceable workaround for a getting and setting a private field or property.

It really isn’t going to perform well, since it uses Reflection, but if it is a single value that you only set once, you won’t have a performance problem.

Since it is so easy to break encapsulation with Reflection, it makes me wonder what the point of encapsulation is in C#? But it still has it’s purposes, I know.


Tips for using the Google Calendar API with C#

See my previous post: Interfacing with the Google Calendar API using C#

Tip #1 – Google Calendar API is set to ReadOnly in the example

I needed to edit, not just read.
Change line 23 in the code above:

//static string[] Scopes = { CalendarService.Scope.CalendarReadonly }; // I needed more than read only
static string[] Scopes = { CalendarService.Scope.Calendar };

Tip #2 – Your App’s Security Permission to use the Google Calendar API

My application stopped working. I had to revoke my projects permission and then run the code again so I was prompted to accept permission. Sometimes I had to re-run the code twice to get the prompt.

Go here to revoke your permissions: https://security.google.com/settings/security/permissions

Tip #3 – How to find a Calendar by name

You can get a list of Calendars. The Summary property is where the Calendar title is stored.

    // . . . Authentication here

    // Create Calendar Service.
    var service = new CalendarService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
    });


    var list = service.CalendarList.List().Execute();
    var myCalendar = list.Items.SingleOrDefault(c => c.Summary == "My Calendar Name");
            
    // . . . do stuff with your calendar

Tip #4 – How to add an event

I thought it was weird that the example didn’t actually have you add an event. To add an event:

  1. First read Tip #1.
  2. Use this code:
    var list = service.CalendarList.List().Execute();
    var myCalendar = list.Items.SingleOrDefault(c => c.Summary == "My Calendar");
            
    if (myCalendar != null)
    {
        Event calEvent = new Event
        {
            Summary = "Awesome Party",
            Location = "My House",
            Start = new EventDateTime
            {
                DateTime = new DateTime(2015, 5, 20, 19, 00, 0)
            },
            End = new EventDateTime
            {
                DateTime = new DateTime(2015, 5, 20, 23, 59, 0)
            },
            Recurrence = new List<string>()
        };
        var newEventRequest = service.Events.Insert(calEvent, myCalendar.Id);
        var eventResult = newEventRequest.Execute();
    }

Interfacing with the Google Calendar API using C#

I needed to script something with Google Calendar, so naturally I headed over to their API page. I found a quick start document and it is a creative commons license, so I can re-post it here:

See my tips after you read this document! See my previous post: Tips for using the Google Calendar API with C#

—————-
Complete the steps described in the rest of this page, and in about five minutes you’ll have a simple .NET console application that makes requests to the Google Calendar API.

Prerequisites

To run this quickstart you’ll need:

  • Visual Studio 2013 or later.
  • Access to the internet and a web browser.
  • A Google account with Google Calendar enabled.

Step 1: Enable the Calendar API

  1. Use this wizard
    to create or select a project in the Google Developers Console and
    automatically enable the API.
  2. In the sidebar on the left, select Consent screen. Select an
    EMAIL ADDRESS and enter a PRODUCT NAME if not already set and click
    the Save button.
  3. In the sidebar on the left, select Credentials and click Create new
    Client ID
    .
  4. Select the application type Installed application, the installed
    application type Other, and click the Create Client ID button.
  5. Click the Download JSON button under your new client ID. Rename it
    to client_secret.json.

Step 2: Install the Google Client Library

  1. Create a new Visual C# Console Application project in Visual Studio.
  2. From the Package Manager Console, with package source set to “nuget.org”
    run the following command:
PM> Install-Package Google.Apis.Calendar.v3

Step 3: Set up the sample

  1. Copy client_secret.json (downloaded in Step 1) into your project directory.
  2. Refresh the Solution Explorer to show the client_secret.json that was
    copied in.
  3. From Solution Explorer right click on client_secret.json and select
    the Include In Project option.
  4. With client_secret.json still selected go to the Properties window and set
    the Copy to Output Directory field to Copy always.
  5. Replace the contents of Program.cs with the following code.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CalendarQuickstart
{
  /// <summary>
  /// Google Calendar API quickstart application that retrieves the next ten
  /// events of the authenticated user's primary calendar and prints the
  /// summary and start datetime/date of each.
  /// </summary>
  class Program
  {
    static string[] Scopes = { CalendarService.Scope.CalendarReadonly };
    static string ApplicationName = "Calendar API Quickstart";


    static void Main(string[] args)
    {
      UserCredential credential;

      using (var stream = new FileStream("client_secret.json", FileMode.Open,
          FileAccess.Read))
      {
        string credPath = System.Environment.GetFolderPath(System.Environment
          .SpecialFolder.Personal);
        credPath = Path.Combine(credPath, ".credentials");

        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
           GoogleClientSecrets.Load(stream).Secrets,
          Scopes,
          "user",
          CancellationToken.None,
          new FileDataStore(credPath, true)).Result;

        Console.WriteLine("Credential file saved to: " + credPath);
      }

      // Create Calendar Service.
      var service = new CalendarService(new BaseClientService.Initializer()
      {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
      });

      // Define parameters of request.
      EventsResource.ListRequest request = service.Events.List("primary");
      request.TimeMin = DateTime.Now;
      request.ShowDeleted = false;
      request.SingleEvents = true;
      request.MaxResults = 10;
      request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;

      Console.WriteLine("Upcoming events:");
      Events events = request.Execute();
      if (events.Items.Count > 0)
      {
        foreach (var eventItem in events.Items)
        {
          string when = eventItem.Start.DateTime.ToString();
          if (String.IsNullOrEmpty(when))
          {
            when = eventItem.Start.Date;
          }
          Console.WriteLine("{0} ({1})", eventItem.Summary, when);
        }
      }
      else
      {
        Console.WriteLine("No upcoming events found.");
      }
      Console.Read();
    }
  }
}

Step 4: Run the sample

Run the sample by clicking Start in the Visual Studio toolbar.

The first time you run the sample it will prompt you to authorize access.

  1. A browser window will open prompting you to login if you are not already
    logged into your Google account. If you are logged into multiple Google
    accounts, you will be asked to select one account to use for the authorization.
  2. Click the Accept button.

Authorization information is stored on the file system, so subsequent
executions will not prompt for authorization.

Further reading

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies.


The Three-Minute Standup

We should all strive for the three-minute standup. If you stand up is different than this, you are doing it wrong:

Manager: Hey, all, let's start standup.

Manager: (looks at Dev 1) Kanban board says you moved Blah task to done yesterday and pulled in foo task today.
Dev 1: Yes.
Manager: Good work. Need anything from me or the team.
Dev 1: No

Manager: (looks at Dev 2) Kanban board says you moved Oober1 task to done yesterday and pulled in Gobblygook task today.
Dev 2: Yes.
Manager: Need anything from me or the team.
Dev 2: Yes, I need help from Dev 1 to do Gobblygook.
Manager: (looks at Dev 1) Dev 1, can you talk to Dev 2 about gobblygook after standup.
Dev 1: Yes

Manager: (looks at Dev 3) Kanban board says you moved Whatsit task to done yesterday and pulled in WrongWork task today.
Dev 3: Oops. Yes, I finished Whatsit yesteday, but I pulled in the wrong story. I am working on RightWork.
Manager: Fix the Kanban board mistake. Need anything from me or the team on RightWork.
Dev 3: Nope

Manager: (Looks at Tester) Kanban board says you finished tests for oober1 and you are working on testing Blah.
Tester: Yes, there was one bug, I verbally told Dev 2, he fixed it. I retested and all tests pass. I am testing Blah now.
Manager: Good work. Need anything from me or the team.
Tester: I'll maybe need to speek to Dev 1 about Blah sometime after lunch.

Manager: Great job team. Keep up the good work.

Stand up ends.

Notice the key to a successful standup is the Kanban board (or Scrum task board). You shouldn’t ever have to explain what you are working on, it is on the board.

If you don’t have a Kanban board or task board, get one immediately.


Setting File Properties in a NuGet Package: Build Action, Copy to Output Directory, Custom Tool

So I have a bunch of files in a NuGet package that need the File Properties set as follows:

Build Action Content
Copy to Output Directory Copy if newer
Custom Tool
Custom Tool Namespace

I am using the NuGet package Project that you can find in the Online projects.

I was able to set these values in a NuGet package as follows using the Install.ps1 PowerShell script. I found this out thanks to Workabyte’s answer on StackOverflow

$item = $project.ProjectItems.Item("MyContentFile.xml")
$item.Properties.Item("BuildAction").Value = 2
$item.Properties.Item("CopyToOutputDirectory").Value = 2
$item.Properties.Item("CustomTool").Value = ""

I would just set something to what I wanted it to be, then I would look at its value.

Here is my full Install.ps1

# Runs every time a package is installed in a project

param($installPath, $toolsPath, $package, $project)

# $installPath is the path to the folder where the package is installed.
# $toolsPath is the path to the tools directory in the folder where the package is installed.
# $package is a reference to the package object.
# $project is a reference to the project the package was installed to.

function SetFilePropertiesRecursively
{
	$folderKind = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}";
	foreach ($subItem in $args[0].ProjectItems)
	{
		$path = $args[1]
	    if ($subItem.Kind -eq $folderKind)
		{
			SetFilePropertiesRecursively $subItem ("{0}{1}{2}" -f $path, $args[0].Name, "\")
		}
		else
		{
			Write-Host -NoNewLine ("{0}{1}{2}" -f $path, $args[0].Name, "\")
			SetFileProperties $subItem 2 2 ""
		}
	}
}

function SetFileProperties
{
	param([__ComObject]$item, [int]$buildAction, [int]$copyTo, [string]$customTool)
	Write-Host $item.Name
	Write-Host "  Setting Build Action to Content"
	$item.Properties.Item("BuildAction").Value = $buildAction
	Write-Host "  Setting Copy To Output Directory to Copy if newer"
	$item.Properties.Item("CopyToOutputDirectory").Value = $copyTo
	Write-Host "  Setting Custom Tool to blank"
	$item.Properties.Item("CustomTool").Value = $customTool
}

SetFilePropertiesRecursively $project.ProjectItems.Item("Globalization")
SetFilePropertiesRecursively $project.ProjectItems.Item("Styles")
SetFileProperties $project.ProjectItems.Item("App.xaml") 4 0 "MSBuild:Compile"

Life is good.


Putting Code in Blog Comments

To put code in comments, you can use the Syntax Highlighter tags common to WordPress.

[code language="csharp"]
your code here
[/code]

Or for shorthand, you can do this:
[csharp]
your code here
[csharp]

Here is an example:

[csharp]
using System;

namespace FnoSharp.DataMigrator
{
     class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}
[csharp]

And it looks like this:

using System;

namespace FnoSharp.DataMigrator
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

The language (or lang) parameter controls how the code is syntax highlighted. The following languages are supported:

  • actionscript3
  • bash
  • clojure
  • coldfusion
  • cpp
  • csharp
  • css
  • delphi
  • erlang
  • fsharp
  • diff
  • groovy
  • html
  • javascript
  • java
  • javafx
  • matlab (keywords only)
  • objc
  • perl
  • php
  • text
  • powershell
  • python
  • r
  • ruby
  • scala
  • sql
  • vb
  • xml

If the language parameter is not set, it will default to “text” (no syntax highlighting).

Code in between the source code tags will automatically be encoded for display, you don’t need to worry about HTML entities or anything.


Row Tests or Paramerterized Tests (MsTest) – Xml

In a previous post, I discussed Parameter Value Coverage (PVC). One of the easiest ways to add PVC to your test suite is to use Row Tests, sometimes called Parameterized Tests. Row test is the idea of writing a single unit test, but passing many different values in.

Different testing frameworks implement row tests differently.

MsTest uses an attribute called DataResourceAttribute. This supports anything from a csv, Excel file or xml, to a full-blown database.

For a single Unit Test, NUnit’s Row tests are far superior. However, for a larger test project, you will see that DataSourceAttribute with external data sources, scales nicely and compares to NUnits TestCaseSource. However, it is not as easy to get it right the first time. It needs a step by step tutorial.

Step 1 – Create a the Project

  1. In Visual Studio click File | New | Project.
  2. Select Unit Test Project for C#.
  3. Give it a name and a path and click OK.

Step 2 – Add an Xml file

  1. Create a folder in your visual studio project called Data.
  2. Right-click on the data folder and choose Add | New Item.
  3. Create new Xml file named: Data.xml
  4. Add the following to the Xml.
<?xml version="1.0" encoding="utf-8" ?>
<Rows xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:x="urn:Row">
  <!-- Schema -->
  <xsd:schema targetNamespace="urn:Row" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="Row">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element type="xsd:int" name="Value1"/>
          <xsd:element type="xsd:int" name="Value2"/>
          <xsd:element type="xsd:int" name="ExpectedValue"/>
          <xsd:element type="xsd:string" name="Message"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <!--End Schema-->
  <x:Row>
    <x:Value1>3</x:Value1>
    <x:Value2>2</x:Value2>
    <x:ExpectedValue>2</x:ExpectedValue>
    <x:Message>2 is less than 3</x:Message>
  </x:Row>
  <x:Row>
    <x:Value1>-1</x:Value1>
    <x:Value2>0</x:Value2>
    <x:ExpectedValue>-1</x:ExpectedValue>
    <x:Message>-1 less than 0</x:Message>
  </x:Row>
  <x:Row>
    <x:Value1>10</x:Value1>
    <x:Value2>5</x:Value2>
    <x:ExpectedValue>5</x:ExpectedValue>
    <x:Message>5 is less than 10</x:Message>
  </x:Row>
</Rows>

Note: This Xml is designed as such so the Schema is inline. That allows us to specify the data type.

Step 3 – Set Xml File Properties

The XML file needs to be copied on build.

  1. Right-click on the Xml file and choose Properties.
  2. Change the Copy to output directory to: Copy if newer

Step 4 – Add a Unit Test method

Note: We won’t have a real project to test. We will just test Math.Min() for an example.

  1. Add a reference to System.Data.
  2. Add the TestContext property. (See line 9 below)
  3. Add a DataSource attribute to the test method. (See line 12 below)
    Notice that is uses Row not Rows (it doesn’t use the root element but the second element).
  4. Use TestContext.DataRow[0] to get the first column. (See line 16 below)
    Note: You can also access the column by the column name we used: TestContext.DataRow[Value1]

  5. Assign variables for the rest of the columns. (See lines 16-19 below)
  6. Add the test and the assert. (See lines 22 and 25)
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MsTestRowTestXml
{
    [TestClass]
    public class UnitTest1
    {
        public TestContext TestContext { get; set; }

        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", @"Data\Data.xml", "Row", DataAccessMethod.Sequential)]
        public void TestMethod1()
        {
            // Arrange
            int a = (int)TestContext.DataRow[0];
            int b = (int)TestContext.DataRow[1];
            int expected = (int)TestContext.DataRow[2];
            string message = TestContext.DataRow[3].ToString();

            // Act
            var actual = Math.Min(a, b);

            // Assert
            Assert.AreEqual(expected, actual, message);
        }
    }
}

You finished! Good job!.

Use Common Xml files for Parameter Value Coverage

While this method involved way more steps than anything with NUnit to set up, tt can actually be a bit quicker for subsequent tests and quite useful when testing larger projects. Once you have the Xml files setup, you can reuse them for many methods. For example, for every method that takes a long, you could use the same DataSource to get Parameter Value Coverage (PVC).

<?xml version="1.0" encoding="utf-8" ?>
<Rows xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:x="urn:Row">
  <!-- Schema -->
  <xsd:schema targetNamespace="urn:Row" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="Row">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element type="xsd:long" name="Value"/>
          <xsd:element type="xsd:string" name="Message"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <!--End Schema-->
  <x:Row>
    <x:Value>2147483648</x:Value>
    <x:Message>One more than int.MaxValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-2147483649</x:Value>
    <x:Message>One less than int.MinValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>9223372036854775807</x:Value>
    <x:Message>long.MaxValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-9223372036854775808</x:Value>
    <x:Message>long.MinValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>0</x:Value>
    <x:Message>0 (zero)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>1</x:Value>
    <x:Message>1 (one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>2</x:Value>
    <x:Message>2 (one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-1</x:Value>
    <x:Message>-1 (minus one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-2</x:Value>
    <x:Message>-2, -2 (minus one)</x:Message>
  </x:Row>
</Rows>

Row Tests or Paramerterized Tests (MsTest) – CSV

In a previous post, I discussed Parameter Value Coverage (PVC). One of the easiest ways to add PVC to your test suite is to use Row Tests, sometimes called Parameterized Tests. Row test is the idea of writing a single unit test, but passing many different values in.

Different testing frameworks implement row tests differently.

MsTest uses an attribute called DataResourceAttribute. This supports anything from a csv, Excel file or xml, to a full-blown database.

For a single Unit Test, NUnit’s Row tests are far superior. However, for a larger test project, you will see that DataSourceAttribute with external data sources, scales nicely and compares to NUnits TestCaseSource. However, it is not as easy to get it right the first time. It needs a step by step tutorial.

Step 1 – Create a the Project

  1. In Visual Studio click File | New | Project.
  2. Select Unit Test Project for C#.
  3. Give it a name and a path and click OK.

Step 2 – Add a csv file

  1. Create a folder in your visual studio project called Data.
  2. Right-click on the data folder and choose Add | New Item.
  3. Create new text file named: Data.csv
  4. Add the following to the csv.
Value1, Value2, ExpectedMinValue, Message
1,10, 1, 1 is less th an 10.
192, 134, 134, 134 is less than 192.
101, 99, 99, 99 is less than 101.
77, 108, 77, 77 is less than 108.
45, 37, 37, 37 is less than 34.
12, 18, 12, 12 is less than 18.

Step 3 – Save the CSV file with the correct encoding

Note: The CSV file needs to be saved with an encoding that doesn’t add junk characters.

  • Click File | Advanced Save Options.
  • Choose this Encoding option: Unicode (UTF-8 without signature) – Codepage 65001
  • Click OK and then click save.
  • Step 4 – Set CSV File Properties

    The CSV file needs to be copied on build.

    1. Right-click on the CSV file and choose Properties.
    2. Change the Copy to output directory to: Copy if newer

    Step 5 – Add a Unit Test method

    Note: We won’t have a real project to test. We will just test Math.Min() for an example.

    1. Add a reference to System.Data.
    2. Add the TestContext property. (See line 9 below)
    3. Add a DataSource attribute to the test method. (See line 12 below)
    4. Use TestContext.DataRow[0] to get the first column. (See line 16 below)
      Note: You can also access the column by the column name we used: TestContext.DataRow[Value1]

    5. Assign variables for the rest of the columns. (See lines 16-19 below)
    6. Add the test and the assert. (See lines 22 and 25)
    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace MsTestRowTestExample
    {
        [TestClass]
        public class UnitTest1
        {
            public TestContext TestContext { get; set; }
    
            [TestMethod]
            [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", @"Data\Data.csv", "Data#csv", DataAccessMethod.Sequential)]
            public void TestMethod1()
            {
                // Arrange
                int a = Convert.ToInt32(TestContext.DataRow[0]);
                int b = Convert.ToInt32(TestContext.DataRow[1]);
                int expected = Convert.ToInt32(TestContext.DataRow[2]);
                string message = TestContext.DataRow[3].ToString();
    
                // Act
                var actual = Math.Min(a, b);
    
                // Assert
                Assert.AreEqual(expected, actual, message);
            }
        }
    }
    

    You finished! Good job!.

    Use Common Csv files for Parameter Value Coverage

    While this method involved way more steps than anything with NUnit to set up, tt can actually be a bit quicker for subsequent tests and quite useful when testing larger projects. Once you have the csv files setup, you can reuse them for many methods. For example, for every method that takes a string, you could use the same DataSource to get Parameter Value Coverage (PVC).

    null, A null string
    "", An empty string, String.Empty, or ""
    " ", One or more spaces " "
    "	", One or more tabs "	"
    "
    ", A new line or Environment.NewLine
    "Hello, world!", A valid string.
    "&*^I#UYLdk1-KNnS1.,Dv0Hhfwelfnzsdase", An invalid or junk string
    গঘ, Double-byte Unicode characters
    

    Row Tests or Paramerterized Tests (NUnit)

    In a previous post, I discussed Parameter Value Coverage (PVC). One of the easiest ways to add PVC to your test suite is to use Row Tests, sometimes called Parameterized Tests. Row test is the idea of writing a single unit test, but passing many different values in.

    Different testing frameworks implement row tests differently.

    NUnit has two options. The first implements them inline, with an attribute for each. Here is an example straight from NUnit’s website:

    [TestCase(12,3,4)]
    [TestCase(12,2,6)]
    [TestCase(12,4,3)]
    public void DivideTest(int n, int d, int q)
    {
        Assert.AreEqual( q, n / d );
    }
    

    NUnit also implements a TestCaseSource attribute.

    [Test, TestCaseSource("DivideCases")]
    public void DivideTest(int n, int d, int q)
    {
        Assert.AreEqual( q, n / d );
    }
    
    static object[] DivideCases =
    {
        new object[] { 12, 3, 4 },
        new object[] { 12, 2, 6 },
        new object[] { 12, 4, 3 }
    };
    

    For a single Unit Test, NUnit’s Row tests are far superior. However, for a larger test project, you will see that TestCaseSource with with data sources, scales nicely. Imagine you have 10 test method that each take in the same 10 lines of data. With the TestCase attribute, you would have to write 10 attributes on all 10 test methods–that is 100 lines of attributes alone. Worse these are 10 exact code copies. That breaks the Don’t Repeat Yourself (DRY) principle of coding. With TestCaseSource, you implement the data for the Row tests in a single place and you add one attribute per test method.

    Hint: Also, you might find many row test sources can be reused for other tests. Maybe storing them in a single data source repository would be a good idea, so they can be reused. Don’t do it for small tests. Only do it for large test projects that need to scale.


    Combining multiple WSDLs for consumption in a C# client project

    So I added a WebReference for nine different web services. These were all web services for the same product. I will call them from the same client code. So it makes sense to consume them all. Each service got it’s own namespace. Immediately there were problems. Multiple web services exposed the same object. Each instance of the object was in a different namespace. This created a bunch of ambiguous reference errors. Fixing those errors made a mess of the code as I then had to include the namespaces when calling the objects or else have object using statements to determine which object to use in which namespace.

    The I got smart and researched combining WSDLs. I found this MSDN site: Web Services Description Language Tool (Wsdl.exe)

    Turns out that Visual Studio comes with a WSDL.exe. It allows for easily combining multiple WSDLs into one large auto-generated code file. It also has a nice parameter called sharetypes. I bet you can guess what sharetypes does.

    Step 1 – Create a wsdl parameters file

    Here is an exmaple of mine.

    1. I left the settings from the MSN example for nologo, parsableerrors, and sharetypes.
      Note: Setting sharetypes to true is the feature I most needed.
    2. Set it to get the URL from the web.config or app.config.
    3. Set the namespace.
    4. Add a document for each wsdl file.
    5. Set out file.
      <wsdlParameters xmlns="http://microsoft.com/webReference/">
        <appSettingUrlKey>FnoSharpWebServiceUrl</appSettingUrlKey>
        <appSettingBaseUrl>FnoSharpWebServiceBaseUrl</appSettingBaseUrl>
        <namespace>FnoSharp</namespace>
        <nologo>true</nologo>
        <parsableerrors>true</parsableerrors>
        <sharetypes>true</sharetypes>
        <documents>
          <document>http://MyServer:8888/flexnet/services/ActivationService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/AdminService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/EntitlementOrderService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/FlexnetAuthentication?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/LicenseService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/ManageDeviceService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/ProductPackagingService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/UserOrgHierarchyService?wsdl</document>
          <document>http://MyServer:8888/flexnet/services/Version?wsdl</document>
        </documents>
        <out>FnoSharpReference.cs</out>
      </wsdlParameters>
      

    Step 2 – Run wsdl.exe

    1. Open a Developer Command Prompt.
    2. Run this command:
      wsdl.exe /Parameters:FnoSharpWsdls.xml
      

    Now you have a single Reference.cs file that includes code for all your WSDLs.

    Step 3 – Update your Visual Studio Project

    1. Delete all your web references.
    2. Add the Reference.cs to your project
    3. Fix your namespaces.

    Step 4 – Update URL to use an appSetting

    Having a hard coded URL in the code is not a good idea. The Reference.cs file you created will have static URLs. Unfortunately the wsdl.exe doesn’t seem to support doing this for multiple urls. So you should manually replace them.

    1. Add a variable to your appSettings in your web.config or app.config.
      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        <appSettings>
          <add key="FnoSharpHost" value="http://MyServer:8888"/>
        </appSettings>
      
        <!-- Other config stuff -->
      
      <configuration>
      
    2. Find and replace all the lines that call your hard coded URL. They look like this. I had 9 WSDLs so I had 9 of these to replace.
          public ActivationService() {
              this.Url = "http://MyServer:8888/flexnet/services/ActivationService";
          }
      

      Here is your find and replace string:

         Find:  this.Url = "http://MyServer:8888
      Replace:  this.Url = ConfigurationManager.AppSettings["FnoSharpHost"] + "
      

      Your methods should now look like this:

          public ActivationService() {
              this.Url = ConfigurationManager.AppSettings["FnoSharpHost"] + "/flexnet/services/ActivationService";
          }
      

    Your done. You now have all your WSDLs combined into one Reference.cs file.