Friday, January 12

Anti-tests

Charles Miller describes the concept of an "Anti-Test", which is a test that verifies a bug exists.

This can be written when the problem is discovered, even if it's not going to be fixed immediately.

It means that if the problem is inadvertently fixed as a result of something else, we know this has happened, have a look at why this is the case and update our records accordingly. The test can then be changed to a normal test to make sure it doesn't go wrong again.

When you're ready to fix an anti-test, you can change it to a normal test - it should now fail (and this change should be easy to make), fix the bug and make sure the test passes.

NAnt version

I've been trying to add version numbers to a NAnt build script using the <version> task, and come across a problem with the script in Marc Holmes' "Expert .NET delivery" book.

The task increments a property called "buildnumber.version", not "sys.version". Adding the following line to the script (as described here) seems to fix it.

<property name="sys.version" value="${buildnumber.version}" />

Sunday, December 3

Using attributes to specify the contents of a menu

Most people think it is a good idea to separate business and presentation logic in your application, so you can update one without changing the other. When you create an application with a menu bar, the menu items will often call functions in your business logic, and if you add a new business logic function you will need to add a handler in your presentation layer and the business logic function in your business logic layer.


This article describes how you can add attributes in your business logic layer and have these dynamically bound to a menu when your application runs. The attributes will look like the following:


   public class MenuHandler
{
[MenuOption ("Menu Option 1")]
public void MenuHandler(object sender,
EventArgs e)
{
//Business Logic
}
}


Creating your Attribute

The first thing you need to do is to set up your attribute. Create a class derived from System.Attribute as follows.


    [AttributeUsage(AttributeTargets.Method)]
public class MenuOptionAttribute :
System.Attribute
{
private string MenuText;

public MenuOptionAttribute(String
menutext)
{
MenuText = menutext;
}

public string GetMenuText
{
get
{
return MenuText;
}
}
}


The first line of this specifies your attribute can be applied to methods (and not to classes). The constructor takes one argument, which is a string representing the menu text.


Applying your attribute to your business logic

Next, you write your business logic layer to use the MenuOption attribute. All you need to do is to put this before any functions you want on your menu, with the text to go on your menu:


    public class BusinessLogic
{
[MenuOption ("Menu Option 1")]
public void Option1(object sender,
EventArgs e)
{
// Option 1 code
}

[MenuOption("Option 2")]
public void Option2(object sender,
EventArgs e)
{
// Option 2 code
}

You can add as many of these functions as you like.


Setting up your menu

Finally, you need to create your presentation layer. You can drag a MenuStrip to a form and add a title for your drop down menu. If you call the title "Main", when you add the title, it will create a ToolStripMenuItem, called "mainToolStripMenuItem" by default.


You need to use reflection to iterate over all the methods in the MenuHandler class, and see which of those methods have the MenuOptionAttribute attribute set.


If it is set, you need to call the GetMenuText() function on the attribute to find out the text to display on the menu bar and add the menu item.


Next, you need to create a delegate to your method.


Finally, you add the event handler to your newly created menu item. It's easier to understand this if you read the code example.


  public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
BusinessLogic bl = new BusinessLogic();

mainToolStripMenuItem.DropDownItems.
Clear();
foreach (MethodInfo method in
(typeof (BusinessLogic)).GetMethods())
{
foreach (object attribute in
method.GetCustomAttributes(true))
{
if (attribute is
MenuOptionAttribute)
{
ToolStripItem newitem =
mainToolStripMenuItem.DropDownItems.Add((
attribute as MenuOptionAttribute).GetMenuText);
EventInfo ci = typeof
(ToolStripItem).GetEvent("Click");
Type tdelegate = ci.
EventHandlerType;
Delegate del = Delegate.
CreateDelegate(tdelegate,bl,method);
ci.AddEventHandler(
newitem, del);
}
}
}
}
}

You could add some code to your attribute to specify its position, and use this to order your menu items. You might want to specify more than one string, one for the heading and one for the item itself, so you can put menu items in under different headings.

Saturday, October 21

InternalsVisibleToAttribute and Unit Testing

When creating unit tests to be run with NUnit, I like to keep my tests in a separate assembly, which is not delivered when my project is deployed.

This can make it difficult to create unit tests for classes that should not be visible outside of that assembly. One of my classes uses one of 3 strategy classes that encapsulate a feature of the business logic. I would normally declare these with the intern access modifier, but to test each strategy works I've needed to make them publically available.

If, however, I add the [assembly: InternalsVisibleTo("UnitTests")] line to my AssemblyInfo.cs file, any objects declared with the intern access modifier can be seen by the UnitTests assembly.

Tuesday, October 10

Processes and Practices

Jared Richardson describes a process he wants his team to follow. Many others have attempted the same and have reached similar conclusions, and I can't disagree with any of Jared's thoughts.

However, I think he misses out the most important part of the process which should be to regularly think about your process and what you have done and how you could have done it better. All processes and practices should be adaptable. Different people have different strengths and new technologies mean we have to develop things in different ways.

A lot has been written about technical debt, where if not enough time is invested in developing high quality software, it becomes harder to maintain and costs of new developments increase over time. We should also think about process debt, where if not enough time is spent improving and adapting our processes, they become less efficient and costs of new developments also increase.

C# collection classes performance

I was looking for a table summarizing how different C# generic and non-generic collection classes performed, relative to one another, thought there would be hundreds available, but could not find one. So here one is for my future reference, and for anyone else who reads this.



O(1) = constant time
O(log n) = time proportional to the log of the number of elements in the collection
O(n) = time proportional to the number of elements in the collection

Some collections are better for smaller collections, but don't scale to larger ones. The List, LinkedList, SortedList, Queue and Stack classes are better for smaller collections than the Dictionary, Hashtable and SortedDictionary classes.

Wednesday, October 4

The type or namespace name 'Properties' could not be found

I was getting an error message when building my project that said "The type or namespace name 'Properties' could not be found".

This was because I had changed the default namespace in the properties for my project to make it "project.name" instead of "name". The class that did not build was already in the namespace "project.name".

The error message was on a line that said

"global::name.Properties.Resources...."

Changing this to

"global::project.name.Properties.Resources...."

seemed to fix the problem.