views:

1371

answers:

3

I have written a few MSBuild custom tasks that work well and are use in our CruiseControl.NET build process.

I am modifying one, and wish to unit test it by calling the Task's Execute() method.

However, if it encounters a line containing

Log.LogMessage("some message here");

it throws an InvalidOperationException:

Task attempted to log before it was initialized. Message was...

Any suggestions? (In the past I have mostly unit-tested Internal static methods on my custom tasks to avoid such problems.)

+3  A: 

If you have implemented the interface ITask you will have to initialise the Log class yourself.

Otherwise you should just inherit from Task in Microsoft.Build.Utilities.dll That implements ITask and does a lot of the leg work for you.

Here is the reference page for building a custom task, it explains quite a lot of it.

Building a custom MSBuild task reference

Also worth a look is

How to debug a custom MSBuild task

Other then that could you post the MSBuild XML you are using for calling your custom task. The code itself would obviously be the most help :-)

evilhomer
+1 ... nice links
alexandrul
+2  A: 

I have found that the log instance does not work unless the task is running inside msbuild, so I usually wrap my calls to Log, then check the value of BuildEngine to determin if I am running inside msbuild. As below.

Tim

private void LogFormat(string message, params object[] args)
{
    if (this.BuildEngine != null)
    {
     this.Log.LogMessage(message, args);
    }
    else
    {
     Console.WriteLine(message, args);
    }
}
Tim Bailey
+9  A: 

You need to set the .BuildEngine property of the custom task you are calling.

You can set it to the same BuildEngine your current task is using to include the output seamlessly.

Task myCustomTask = new CustomTask();
myCustomTask.BuildEngine = this.BuildEngine;
myCustomTask.Execute();
Branstar
This was exactly what I needed - thanks!
Jarrod Dixon
Since the question was in the context of a unit test, I would also add that you can alternatively set the BuildEngine property to a mock/stub object that implements the IBuildEngine interface.
Kiff