Monday, 19 January 2009

NAnt HowTo #4: How To Create And Use Custom NAnt Task

new class named OK, let's start. What is a NAnt task? Formally, it's a class that extends NAnt.Core.Task class from NAnt.Core.dll assembly located in your NAnt installation folder. As any class it will be placed in an assembly, and this assembly is the way you interact with NAnt. So, let's get it! The following steps describe how to create a simple HelloTask task.

1. Create new project

Create an empty class library project that will compile to .dll file.

2. Create new class derived from NAnt.Core.Task

Create new class named HelloTask and derive from NAnt.Core.Task:

public class HelloTask : Task
{

}

3. Override ExecuteTask method

As NAnt.Core.Task class is abstract VS will suggest you to override the ExecuteTask method - do it. Put the following implementation into it (assume that Person property is already defined ;)):

protected override void ExecuteTask()
{
Project.Log(Level.Info, String.Format("Hello, {0}!", Person));
}
Have a look at Project.Log() call - it will output some message with needed level.

4. Define task name

To define task name, you should apply NAnt.Core.Attributes.TaskNameAttribute attribute to your class:
[TaskName("hello")]
public class HelloTask : Task


5. Define task attributes

To define task attributes, you should define property of appropriate type and mark it with the NAnt.Core.Attributes.TaskAttributeAttribute attribute:

[TaskAttribute("person", Required = true)]
public String Person
{
get;
set;
}
Attribute constructor allows you to specify several options, like whether this attribute is required.

6. Load assembly with you class in NAnt

To use your new task you should place your assembly somewhere NAnt has access to. Two most appropriate options are in NAnt installation folder and in build execution folder. Though I prefer the last one, the first one may be useful if you use your custom tasks regularly though not changing them often.

As soon as assembly is properly placed, you should load tasks from it in your build file. Use loadtasks attribute to load it:

<loadtasks assembly="Leaves.NAnt.Custom.dll" />

7. Use your task

Just use it in the most obvious way:

<hello person="world" />
The output will be the following:

all:

[loadtasks] Scanning assembly "Leaves.NAnt.Custom" for extensions.
Hello, world!

It works!

8. Summarize

This is what we've got in our task:

using System;
using NAnt.Core;
using NAnt.Core.Attributes;

namespace Leaves.NAnt.Custom
{
[
TaskName("hello")]
public class HelloTask : Task
{
protected override void ExecuteTask()
{
Project.Log(Level.Info, String.Format("Hello, {0}!", Person));
}

[
TaskAttribute("person", Required = true)]
public String Person
{
get;
set;
}
}
}
And build file:

<?xml version="1.0"?>

<project
name="NAnt HowTo 4" default="all" xmlns="http://nant.sf.net/release/0.85-rc2/nant.xsd">
<target
name="all">
<loadtasks
assembly="Leaves.NAnt.Custom.dll" />
<hello
person="world" />
</target>
</project>
kick it on DotNetKicks.com

Friday, 16 January 2009

ASP.NET MVC impressions

It's awesome! As a fan of Ruby on Rails I can tell you: ASP.NET MVC is f*cking awesome!

Monday, 5 January 2009

NAnt HowTo #3: How To Run NUnit Tests From Your Build File

This post continues my NAnt HowTo series. In previous posts I've covered topics of compiling your project and splitting your build file. Today I want to tell you how to run NAnt unit tests from your NAnt build script.

First of all you may notice that main NAnt distribution has TWO NUnit tasks: nunit and nunit2. First one is designed to work with NUnit 1.0 and second one with NUnit 2.2. This simple moment can warn you that something is not as good as it seems here. And you will be right :) Me personally had a problem running NUnit of some lately version using this nunit2 task. After some googling I've found a solution in Scott Hanselman's blog where he spoke with his friend on same topic. As a result of this conversation Scott recommended using nunit-console.exe instead. I've tried it - it works :) Now changing NUnit version will not break as nunit-console command-line specification is not something to change when switching from 2.x to 2.(x+1).

How can we do this? Simple enough:

<target name="tests.unit.run" description="Run unit tests">
<exec
program="D:/bin/nunit/nunit-console.exe"
workingdir="D:/projects/MyProject/Integration"
commandline="MyProject.Tests.dll /xml:TestResults.xml /nologo"/>
</target>

So, step by step.
  1. We use <exec> task to run an executable. This also means that if our nunit-console.exe executable fails (read: some test fails) it will break our build. Of course, you may use failonerror="false" attribute on your <exec> task but I do not recommend doing so - why would anyone ever need tests if their failure will be ignored?!

  2. We specify path to our nunit-console.exe executable via the program attribute.

  3. We specify working directory (usually it's integration dir where you have all needed assemblies) via the workingdir attribute.

  4. We pass command line parameters via the commandline attribute.
Actually this could be the end of the post but I want to say some words on command line arguments of nunit-console.
  1. First non-keyed (with no preceding /im-a-key: keys) several arguments specify assemblies to run tests from.

  2. Argument after /xml: key is a bit more interesting. It indicates the XML file where test results will be stored. You may not need it at the moment but you'll definitely need this file when you'll be integrating your NAnt build script with CruiseControl.NET or any other integration software.

  3. /nologo key suppresses NUnit copyright information display on each run
You can read more about these command line arguments on the official NUnit website.

That's the end :) Next time I will probably speak on writing NAnt custom tasks. Stay online.


kick it on DotNetKicks.com