teste de unidade MSBuild tarefas personalizado sem “Task tentou fazer logon antes de ser inicializado” erro
-
06-07-2019 - |
Pergunta
Eu escrevi algumas tarefas personalizadas MSBuild que funcionam bem e são de uso em nosso processo CruiseControl.NET construção.
Eu estou modificando um, e desejo de unidade de teste-lo chamando o método do Tarefa Execute ().
No entanto, se ele encontra uma linha contendo
Log.LogMessage("some message here");
ele lança um InvalidOperationException:
Task tentou fazer logon antes de ser inicializado. Mensagem era ...
Todas as sugestões? (No passado, eu ter métodos estáticos internos principalmente testado unidades em minhas tarefas personalizadas para evitar tais problemas.)
Solução
Você precisa definir a propriedade .BuildEngine da tarefa personalizada que você está chamando.
Você pode configurá-lo para o mesmo BuildEngine sua tarefa atual está usando para incluir a saída sem problemas.
Task myCustomTask = new CustomTask();
myCustomTask.BuildEngine = this.BuildEngine;
myCustomTask.Execute();
Outras dicas
Eu descobri que a instância log não funciona, a menos que a execução da tarefa msbuild dentro, assim que eu costumo colocar minhas chamadas para Log, em seguida, verificar o valor da BuildEngine para determin se eu estou correndo dentro msbuild. Como abaixo.
Tim
private void LogFormat(string message, params object[] args)
{
if (this.BuildEngine != null)
{
this.Log.LogMessage(message, args);
}
else
{
Console.WriteLine(message, args);
}
}
@Kiff comentário sobre simulação / stub IBuildEngine é uma boa idéia. Aqui é a minha FakeBuildEngine. C # e VB.NET exemplos fornecidos.
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
C #
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"; }
}
}
Se você implementou a interface ITask você terá que inicializar a classe Log-se.
Caso contrário, você deve apenas herdar de Task em Microsoft.Build.Utilities.dll Que implementa ITask e faz um monte de trabalho de pé para você.
Aqui está a página de referência para a construção de uma tarefa personalizada, explica um monte de-lo.
Construindo um MSBuild referência tarefa personalizada
Também olhar a pena é
Como depurar uma tarefa MSBuild personalizada
Outro então que você poderia postar o XML MSBuild que você está usando para chamar a sua tarefa personalizada. O código em si, obviamente, seria de mais ajuda: -)
Eu tive o mesmo problema. Eu resolvi por arrancar o motor de criação. Assim (AppSettings é o Nome MsBuild Task):
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();
}
}
}
System.Web
montagem em namespace
System.Web.Compilation
é um MockEngine
classe que implementa IBuildEngine
interface
de uma forma que descreve Tim Murphy.