teste de unidade MSBuild tarefas personalizado sem “Task tentou fazer logon antes de ser inicializado” erro

StackOverflow https://stackoverflow.com/questions/260847

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.)

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top