Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, April 19, 2010

Unit test all enum values with NUnit

In an older post I demonstrated NUnit's built-in parameterized tests feature. This allows a developer to call a single method to run multiple tests.

Let's say I want to run the test for each value in an enumeration. Using the TestCase attribute, I can write the test like this:

  [TestCase(Powertools.Chainsaw)]
  [TestCase(Powertools.CircularSaw)]
  [TestCase(Powertools.PowerDrill)]
  public void PowerToolsTestExplicit(Powertools p)
  {
      // Do test
  }

Which is fine, but what if I add a new value to the enum? Instead of having to add another attribute to the test, it would be easier to loop over all enum values at runtime. With the TestCaseSource attribute I can do just that.

Within my unit test class I first create a method that returns an IEnumerable (in this case Array) containing the enum values:

  public Array GetPowerTools()
  {
      return Enum.GetValues(typeof(Powertools));
  }

Then I create my unit test and decorate it with the TestCaseSource attribute. The attribute constructor takes one parameter, sourceName, which is the name of the method to call:

  [TestCaseSource("GetPowerTools")]
  public void PowerToolsTestWithIEnumerable(Powertools p)
  {
      // Do test
  }

In either case, this expands my unit tests as expected. The second method is easier to maintain and less likely to allow untested code into the system.

Friday, November 13, 2009

More than one way to sort a List<>

One operation you occasionally need to perform is sorting a generic list of objects. Often developers code handle with an inline delegate. If I wanted to sort a collection of boardgames by rating, my code might look like this:

  games.Sort(
      delegate(BoardGame a, BoardGame b)
      {
          if (a.Rating < b.Rating)
              return 1;
          if (a.Rating > b.Rating)
              return -1;
          return 0;
      });

Although this works, it tends to look a bit cluttered. It also increases a method's complexity and doesn't adhere to the idea of separation of concerns. If we only need to sort Boardgames in this one location, a better solution is to move the comparison code into a separate method in the same class. The new method looks like this:

  public int CompareBoardgamesByRank(BoardGame a, BoardGame b)
  {
      if (a.Rating < b.Rating)
          return 1;
      if (a.Rating > b.Rating)
          return -1;
      return 0;
  }

Our call to Sort looks like this:

  games.Sort(CompareBoardgamesByRank);

This makes the code much cleaner for a single sort. If we want to sort Boardgames by rating from multiple locations, we need a better place to store the comparison method. If we implement IComparable on our Boardgame class, we can create a CompareTo method on the class like so:

  public int CompareTo(object obj)
  {
      BoardGame b = (BoardGame)obj;
 
      if (Rating < b.Rating)
          return 1;
      if (Rating > b.Rating)
          return -1;
      return 0;
  }

Since the class now has a default comparison, we no longer need to specify a delegate when calling Sort - the CompareTo method will automatically be executed with an empty call:

  games.Sort();

What if we need additional comparison methods for our Boardgame? An easy way to handle this is to create static methods on the class, which will be available anywhere that Boardgame can be accessed. Here are a couple methods I've added to my Boardgame class:

  public static int CompareByName(BoardGame a, BoardGame b)
  {
      return string.Compare(a.Name, b.Name);
  }
 
  public static int CompareByRankAssending(BoardGame a, BoardGame b)
  {
      if (a.Rating > b.Rating)
          return 1;
      if (a.Rating < b.Rating)
          return -1;
      return 0;
  }

Which I can now pass into the Sort method:

  games.Sort(BoardGame.CompareByRankAssending);

Monday, September 21, 2009

Cleaning up enumerations

When working on existing code I occasionally run into an enumeration class similar to this:

  public class PowertoolsConstants
  {
      public enum Powertools
      {
          PowerDrill = 0, // Standard, corded drill
          Chainsaw,       // Everyone's favorite
          CircularSaw     // If the chainsaw is out of gas, use this
      }
 
      public static Powertools ConvertFromString(string s)
      {
          switch (s)
          {
              case "PowerDrill":
                  return Powertools.PowerDrill;
              case "0":
                  return Powertools.PowerDrill;
              case "Chainsaw":
                  return Powertools.Chainsaw;
              case "1":
                  return Powertools.Chainsaw;
              case "CircularSaw":
                  return Powertools.CircularSaw;
              case "2":
                  return Powertools.CircularSaw;
              default:
                  throw new Exception("Unknown Powertool");
          }
      }
 
      public static string ConvertFromPowertool(Powertools p)
      {
          switch (p)
          {
              case Powertools.Chainsaw:
                  return "Chainsaw";
              case Powertools.CircularSaw:
                  return "CircularSaw";
              case Powertools.PowerDrill:
                  return "PowerDrill";
              default:
                  return "Unknown";
          }
      }
  }


Nothing too complex, but it can be cleaned up a bit. For starters, accessing the enum currently requires referencing the class:

  PowertoolsConstants.Powertools tool =
      PowertoolsConstants.Powertools.Chainsaw;


If we move the enum declaration above the class we can remove the class reference:

  Powertools tool = Powertools.Chainsaw;


Next is addressing the two methods in the class: ConvertFromString and ConvertFromPowertool. The purpose of these methods is to switch between our enumeration and a string representation of the enum, perhaps to store values in an xml file or database. As the .Net Framework already contains this functionality, the methods are not necessary and can be deleted.

To convert from an enum value to a string we can use Enum.GetName

  string toolName = Enum.GetName(typeof(Powertools), tool);


To convert from a string to an enum value we can use Enum.Parse. Note that this will throw an ArgumentException if an invalid string is passed in.

  tool = (Powertools)Enum.Parse(typeof(Powertools), toolName);


With the two methods removed, the class PowertoolsConstants is empty and can be deleted.

One final thing to look at are the comments beside the enum values. These appear to be usage notes. If a developer using the enum needs to know this information, he shouldn't have to open this code to get it. The way to correct this is to replace the existing comments with xml-style comments.

  public enum Powertools
  {
      /// <summary>
      /// Standard, corded drill
      /// </summary>
      PowerDrill = 0,
 
      /// <summary>
      /// Everyone's favorite
      /// </summary>
      Chainsaw,
 
      /// <summary>
      /// If the chainsaw is out of gas, use this
      /// </summary>
      CircularSaw
  }


Doing this will provide the developer with Intellisense hints as they code:

Wednesday, August 19, 2009

Parameterized tests in NUnit

In an earlier post I showed how to pass parameters to test methods using an NUnit RowTest extension. As of version 2.5, the extensions are no longer packaged with the NUnit installer. The good news is that the addition of parameterized tests replaces the RowTest and adds a number of new features as well.

For reference, my previous RowTest looked like this:

[RowTest]
[Row(2, 3)]
[Row(-1, -4)]
public void AddTwoNumbers(int x, int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}

A basic switch to a parameterized test is a matter of dropping the RowTest attribute and replacing each Row attribute with a similarly-formatted TestCase attribute. The new code, which creates two distinct tests as before, looks like this:

[TestCase(2, 3)]
[TestCase(-1, -4)]
public void AddTwoNumbers(int x, int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}

In addition to single parameters you can now specify ranges. If I want to test values of X from 1 to 5, with a Y value of 1, I can do so using the Range and Values attributes, like so:

[Test]
public void AddTwoNumbers(
                    [Range(1, 5)]int x,
                    [Values(1)]int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}        

In the test runner, this shows up as five distinct unit tests


If I specify the range 1-5 for both X and Y, NUnit defaults to creating 25 unique tests. This is the default Combinatorial attribute.


If I wish to use a value from each range only once, I instead mark the test as Sequential

[Test, Sequential]
public void AddTwoNumbers(
                    [Range(1, 5)]int x,
                    [Range(1, 5)]int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}        

which produces the desired effect

Wednesday, August 12, 2009

Save WinForm control values between executions

Say I have a test application that submits info to a webservice. Because this webservice has a few issues, I may need to retry a request several times to get a valid response. I've added a control to set the number of retries.


Specifying the control's Value property at design-time sets the starting value at runtime. If a user wants to set a different value, he must do so each time he starts the app. To make things more user-friendly it would be better to save the control's value between executions.

To do so, start by selecting the desired control in the designer. In the Properties window, expand the ApplicationSettings entry and select the ellipsis (...) for the PropertyBinding sub-entry.


In the Application Settings dialog that appears, select the dropdown next to the 'Value' entry, as this is the property we wish to persist.


Select the '(New...)' link from the popup, which brings up the New Application Setting dialog.


Specify the default value and name of the config setting (and modify the Scope if necessary) and press OK. This will update the Application Settings dialog to show the newly added entry.


Press OK to close the dialog. With the property binding set, the application will automatically load the value at startup. The only thing left is to save the modified value. In the form's FormClosing event handler, add the following line:

Properties.Settings.Default.Save();


At this point the change is ready to test. Start the application and modify the control's value. Without doing anything else, close the application. Now restart the app. Note the control contains the modified value.

It would seem the desired functionality is complete but there is one more item that needs to address. If you look for the saved settings file, you will find it under

C:\Documents and Settings\<username>\Local Settings\Application Data\<Company>\<AppName>\<version>

If the version number for the application is changed, the previously saved setting won't be loaded. The application needs to know to upgrade the saved settings the first time it runs.

Start by adding a new application setting called UpgradeSettings. This will be used to make sure we only upgrade the settings once. Otherwise, any newly saved settings will be replaced by the previous version's settings every time the app starts.


The final step is to add the upgrade logic to Program.cs. In the Main method, add the following code immediately before the call to Application.Run.

if (Convert.ToBoolean(Properties.Settings.Default["UpgradeSettings"]))
{
    Properties.Settings.Default.Upgrade();
    Properties.Settings.Default["UpgradeSettings"] = false;
}

Tuesday, July 14, 2009

No-hassle SQL connection strings

Most applications working with a database handle the connection string in one of two ways: Hard-coding the full string or doing some amount of string concatenation. A typical concatenation method looks something like this:

public string OldMethod(string server, string database,
                        string username, string password)
{
    string connectionString = "Data Source=" + server + ";";
    connectionString += "Initial Catalog=" + database + ";";
    connectionString += "User ID=" + username + ";";
    connectionString += "Password=" + password;
 
    return connectionString;
}

I admit this is fairly simple code. The only potential issues might be a property name typo or a misplaced (or missing) semicolon. But why hassle with even that much when the dotNet Framework has the same functionality built into the SqlConnectionStringBuilder class? With a reference to System.Data.SqlClient, the above method can be replaced with:

public string NewMethod(string server, string database,
                        string username, string password)
{
    SqlConnectionStringBuilder connBuilder 
        = new SqlConnectionStringBuilder();
 
    connBuilder.UserID = username;
    connBuilder.Password = password;
    connBuilder.InitialCatalog = database;
    connBuilder.DataSource = server;
 
    return connBuilder.ToString();
}

In either case, the output is identical:

Data Source=myServer;Initial Catalog=myDatabase;User ID=myUser;Password=myPassword

Note: If you are working with a database other than MSSQL, there are several other classes derived from the common DbConnectionStringBuilder base class, such as OdbcConnectionStringBuilder and OracleConnectionStringBuilder.

Monday, July 6, 2009

Quickly escape strings in xml

If you spend much time working with xml, you will find yourself needing to escape strings. Replacing '<' with '&lt;' for example. Usually the code written to do so looks something like this:

escapedItem = itemToEscape.Replace("&", "&amp;")
                          .Replace("<", "&lt;")
                          .Replace(">", "&gt;")
                          .Replace("'", "&apos;")
                          .Replace("\"", "&quot;");

Though this technically works, there is an easier way built right in to the .Net framework. If we reference System.Security we can replace the above code with

escapedItem = SecurityElement.Escape(itemToEscape);

In both cases, the string

If (x < 2) & (y > 3), where \"x\" isn't...

is replaced with

If (x &lt; 2) &amp; (y &gt; 3), where &quot;x&quot; isn&apos;t...

Friday, January 23, 2009

Row tests in NUnit

[Update 8/19/09: As of version 2.5, the extensions are no longer installed with NUnit. See my post on parameterized tests for a replacement.]

File this one under "old features I'm only now learning about." It seems NUnit has had a RowTest extension built in since March of 08...

For example, let's say I have a method called Add that adds two integers and returns the result. (The internals of that method are highly complex and I won't go into details here.) If you wanted to test two positive integers, a unit test would look like this:

[Test]
public void AddTwoPositiveNumbers()
{
    Assert.AreEqual(2 + 3, Add(2, 3), 
        "Add returned incorrect result");
}


To test two negative integers you would historically create a second, nearly identical unit test:

[Test]
public void AddTwoNegativeNumbers()
{
    Assert.AreEqual(-1 + -4, Add(-1, -4), 
        "Add returned incorrect result");
}


For reference, the two tests will appear under the class name when viewed through the NUnit GUI.



Now, these don't seem too bad, but what happens if you needs lots of nearly-identical tests? Or these tests need to perform additional steps? Copy/paste is a bad programming practice, even for unit tests. Fortunately, Nunit provides an extension (under the NUnit.Framework.Extensions namespace not surprisingly) that makes life much easier - the RowTest.

To use, create a single test method with parameters for the varying test data. Decorate the method with a RowTest attribute, and one Row attribute for each test case. The above unit tests can now be replaced by:

[RowTest]
[Row(2, 3)]
[Row(-1, -4)]
public void AddTwoNumbers(int x, int y)
{
    Assert.AreEqual(x + y, Add(x, y), 
        "Add returned incorrect result");
}


Changes to the test set becomes much easier, as does adding new tests. In the GUI, you'll see each Row split out as an individual test beneath the generic test:

Friday, August 29, 2008

Verify user membership in an AD group

Occasionally, when working on a WinForms application, I need to validate the current user against an Active Directory group before letting the application run. Though not a complex task, it usually takes me a bit of time to research (Translation: I have to copy code from several web sites and modify to suit my needs.) So I figured I'd post my own implementation here for others to use in their research. That, and maybe save myself a bit of time in the future.

The first step is to get the list of AD groups the current user belongs to. The magic necessary to make this happen is contained in the System.DirectoryServices namespace. The code to return the list looks like so:


internal static List<string> GetADGroupsForCurrentUser()
{
List<string> groups = new List<string>();
string domainName = Environment.UserDomainName;
DirectoryEntry entry = new DirectoryEntry("LDAP://"
+ domainName);
string filter = "(samAccountName="
+ Environment.UserName + ")";

DirectorySearcher search =
new DirectorySearcher(entry, filter);
search.PropertiesToLoad.Add("memberOf");

SearchResult results = search.FindOne();
int groupsCount = results.Properties.Count;
for (int i = 0; i < groupsCount; i++)
{
string groupString =
results.Properties["memberOf"][i].ToString();
groups.Add(groupString);
}

return groups;
}

Once we have the list, we need to loop through it looking for the desired AD group. The strings returned from the above code contain comma-delimited properties (something like "CN=MyDomainGroup,OU=Security Groups,DC=local".) Because of this I'm using the Contains method to search the string for the desired domain name. I'm sure there's another way to do this, but whatever works...


public static bool CurrentUserIsAuthorized(string authorizedGroupName)
{
List<string> activeDirectoryGroups =
GetADGroupsForCurrentUser();
foreach (string group in activeDirectoryGroups)
{
if (group.Contains(authorizedGroupName))
return true;
}

return false;
}

Sunday, June 22, 2008

Wrapping a class in a singleton

My current task at work has me building a new application, using an existing framework as the base. One of the classes in this framework wraps access to the config file (which is actually kept in the database.) As soon as this class is instantiated, it retrieves the config info from the database. I wanted a way to keep a single instance around for the lifetime of the application. Otherwise, I'd be hitting the database multiple times to pull down the same information.

One option would have been to create an instance in the app's constructor. The downside to that approach is that I'd have to pass it into every method that might need it. Instead I chose to use the singleton pattern.

Below is a quick example. Marking the MyConfig class as static means it can't be instantiated. The static constructor will be called once and only once - the first time the class is accessed. This constructor creates an instance of the CommonConfig class, which can be accessed through the Config property. Now, regardless of how many times my code accesses MyConfig.Config, the database is only hit once.

    public static class MyConfig
    {
        static readonly CommonConfig _commonConfig;
 
        static MyConfig()
        {
            _commonConfig = new CommonConfig();
        }
 
        public static CommonConfig Config
        {
            get
            {
                return _commonConfig;
            }
        }
    }

Friday, October 19, 2007

Implicit conversions

I'm working on a project where request and response messages are serialized before sending across the wire. We do this by calling an override of ToString(). So a line in the code might look like
    response = myProvider.ProcessMessage(myMessage.ToString());

If I try to type
    response = myProvider.ProcessMessage(myMessage);

I get a build error stating that it cannot implicitly convert type 'SomeCoolMessage' to 'string.' So, what if I want to implicitly convert between the two? In the SomeCoolMessage class I add a new operator

    public static implicit operator string(SomeCoolMessage m)
{
return m.ToString();
}

Now I can write
    response = myProvider.ProcessMessage(myMessage);

and everything just works.

Friday, September 21, 2007

WinForms testing using NUnitForms

I've been spending a lot of time lately coding screens for a WinForms application. Although I've written unit tests for the server components, the client side is somewhat lacking. Each time I change a screen I have to manually test those changes and verify I didn't break anything. In an attempt at automating the process, I've started looking at NUnitForms, an extension to NUnit.

Setup

1) Install NUnitForms
2) Create a project for your NUnit tests. Configure NUnit as normal.
3) Add references to your application project, NUnitForms, System.Windows.Forms, and any third-party controls you use on your application's forms.
4) In the test fixtures, add 'using NUnit.Extensions.Forms'

Basic forms testing

Let's say my application under test (AUT) contains a form, Form1. The first step is to create and display an instance of that form


Form1 testForm = new Form1();
testForm.Show();

Say the form has a button - btnOne. Pressing the button programatically looks like this


ButtonTester btnOneTester = new ButtonTester("btnOne");
btnOneTester.Click();

Upon clicking this button, a label was updated with the everyone's favorite power tool. To verify


LabelTester labelOneTester = new LabelTester("labelOne");
Assert.AreEqual("Chainsaw", labelOneTester.Text, "Label text doesn't match expected");

Though it's not required, it's probably a good idea to close the form instead of letting it fall out of scope


testForm.Close();

Using the hidden desktop

Running these tests on your local machine doesn't pose any issues. If you run them on a build server, however, you'll likely find that they fail - there's no window for the forms to be displayed in. Fortunately, you can send them to a hidden desktop.

To do so, your test fixture must inherit from NUnitFormTest. Then, add the following property to the class


public override bool UseHidden
{
get { return true; }
}

One warning - In most of my test fixtures, I tend to put common code in a [Setup] method. I'm finding that when I have this defined, forms are not being sent to the hidden desktop. I've not spent much time on it, so I'm not sure if it's something I'm doing wrong, or if it's a bug in the tool. I'll post more info if/when I figure it out.