c# - Prueba unitaria MSBuild Tarea personalizada sin error "La tarea intentó iniciar sesión antes de que se inicializara"
msbuild-task invalidoperationexception (6)
He escrito algunas tareas personalizadas de MSBuild que funcionan bien y se usan en nuestro proceso de compilación CruiseControl.NET.
Estoy modificando uno y deseo probarlo en una unidad llamando al método Execute () de la tarea.
Sin embargo, si encuentra una línea que contiene
Log.LogMessage("some message here");
arroja una InvalidOperationException:
La tarea intentó iniciar sesión antes de que se inicializara. El mensaje fue ...
¿Alguna sugerencia? (En el pasado, tenía métodos estáticos internos mayormente probados en unidades en mis tareas personalizadas para evitar tales problemas).
Si ha implementado la interfaz ITask, deberá inicializar la clase Log usted mismo.
De lo contrario, simplemente debe heredar de Tarea en Microsoft.Build.Utilities.dll que implementa ITask y hace mucho trabajo por usted.
Aquí está la página de referencia para construir una tarea personalizada, explica bastante.
Crear una referencia de tarea MSBuild personalizada
También vale la pena echar un vistazo
Cómo depurar una tarea personalizada de MSBuild
Aparte de eso, podría publicar el XML de MSBuild que está utilizando para llamar a su tarea personalizada. El código en sí sería obviamente la mejor ayuda :-)
Descubrí que la instancia de registro no funciona a menos que la tarea se esté ejecutando dentro de msbuild, por lo que generalmente cierro mis llamadas a Log, luego verifico el valor de BuildEngine para determinar si estoy ejecutando dentro de msbuild. Como a continuación.
Tim
private void LogFormat(string message, params object[] args)
{
if (this.BuildEngine != null)
{
this.Log.LogMessage(message, args);
}
else
{
Console.WriteLine(message, args);
}
}
Debe establecer la propiedad .BuildEngine de la tarea personalizada a la que está llamando.
Puede establecerlo en el mismo BuildEngine que está utilizando su tarea actual para incluir la salida sin problemas.
Task myCustomTask = new CustomTask();
myCustomTask.BuildEngine = this.BuildEngine;
myCustomTask.Execute();
Comentario de @Kiff en mock / stub IBuildEngine es una buena idea. Aquí está mi FakeBuildEngine. Se proporcionan ejemplos de C # y VB.NET.
VB.NET
Imports System
Imports System.Collections.Generic
Imports Microsoft.Build.Framework
Public Class FakeBuildEngine
Implements IBuildEngine
// It''s just a test helper so public fields is fine.
Public LogErrorEvents As New List(Of BuildErrorEventArgs)
Public LogMessageEvents As New List(Of BuildMessageEventArgs)
Public LogCustomEvents As New List(Of CustomBuildEventArgs)
Public LogWarningEvents As New List(Of BuildWarningEventArgs)
Public Function BuildProjectFile(
projectFileName As String,
targetNames() As String,
globalProperties As System.Collections.IDictionary,
targetOutputs As System.Collections.IDictionary) As Boolean
Implements IBuildEngine.BuildProjectFile
Throw New NotImplementedException
End Function
Public ReadOnly Property ColumnNumberOfTaskNode As Integer
Implements IBuildEngine.ColumnNumberOfTaskNode
Get
Return 0
End Get
End Property
Public ReadOnly Property ContinueOnError As Boolean
Implements IBuildEngine.ContinueOnError
Get
Throw New NotImplementedException
End Get
End Property
Public ReadOnly Property LineNumberOfTaskNode As Integer
Implements IBuildEngine.LineNumberOfTaskNode
Get
Return 0
End Get
End Property
Public Sub LogCustomEvent(e As CustomBuildEventArgs)
Implements IBuildEngine.LogCustomEvent
LogCustomEvents.Add(e)
End Sub
Public Sub LogErrorEvent(e As BuildErrorEventArgs)
Implements IBuildEngine.LogErrorEvent
LogErrorEvents.Add(e)
End Sub
Public Sub LogMessageEvent(e As BuildMessageEventArgs)
Implements IBuildEngine.LogMessageEvent
LogMessageEvents.Add(e)
End Sub
Public Sub LogWarningEvent(e As BuildWarningEventArgs)
Implements IBuildEngine.LogWarningEvent
LogWarningEvents.Add(e)
End Sub
Public ReadOnly Property ProjectFileOfTaskNode As String
Implements IBuildEngine.ProjectFileOfTaskNode
Get
Return "fake ProjectFileOfTaskNode"
End Get
End Property
End Class
DO#
using System;
using System.Collections.Generic;
using Microsoft.Build.Framework;
public class FakeBuildEngine : IBuildEngine
{
// It''s just a test helper so public fields is fine.
public List<BuildErrorEventArgs> LogErrorEvents = new List<BuildErrorEventArgs>();
public List<BuildMessageEventArgs> LogMessageEvents =
new List<BuildMessageEventArgs>();
public List<CustomBuildEventArgs> LogCustomEvents =
new List<CustomBuildEventArgs>();
public List<BuildWarningEventArgs> LogWarningEvents =
new List<BuildWarningEventArgs>();
public bool BuildProjectFile(
string projectFileName, string[] targetNames,
System.Collections.IDictionary globalProperties,
System.Collections.IDictionary targetOutputs)
{
throw new NotImplementedException();
}
public int ColumnNumberOfTaskNode
{
get { return 0; }
}
public bool ContinueOnError
{
get
{
throw new NotImplementedException();
}
}
public int LineNumberOfTaskNode
{
get { return 0; }
}
public void LogCustomEvent(CustomBuildEventArgs e)
{
LogCustomEvents.Add(e);
}
public void LogErrorEvent(BuildErrorEventArgs e)
{
LogErrorEvents.Add(e);
}
public void LogMessageEvent(BuildMessageEventArgs e)
{
LogMessageEvents.Add(e);
}
public void LogWarningEvent(BuildWarningEventArgs e)
{
LogWarningEvents.Add(e);
}
public string ProjectFileOfTaskNode
{
get { return "fake ProjectFileOfTaskNode"; }
}
}
Yo tuve el mismo problema. Lo solucioné apagando el motor de construcción. Al igual que (AppSettings es el nombre de tarea de MsBuild):
using Microsoft.Build.Framework;
using NUnit.Framework;
using Rhino.Mocks;
namespace NameSpace
{
[TestFixture]
public class Tests
{
[Test]
public void Test()
{
MockRepository mock = new MockRepository();
IBuildEngine engine = mock.Stub<IBuildEngine>();
var appSettings = new AppSettings();
appSettings.BuildEngine = engine;
appSettings.Execute();
}
}
}
En ensamble System.Web
en el namespace
de namespace
System.Web.Compilation
es una clase MockEngine
que implementa la interface
IBuildEngine
de una manera que describe a Tim Murphy.