2008-11-04 5 views
25

잘 작동하고 CruiseControl.NET 빌드 프로세스에서 사용하는 몇 가지 MSBuild 사용자 지정 작업을 작성했습니다.단위 테스트 MSBuild 사용자 지정 작업 "작업이 초기화되기 전에 기록하려고했습니다"오류

하나를 수정 중이며 작업의 Execute() 메서드를 호출하여 단위 테스트를 수행하고 싶습니다. 이

Log.LogMessage("some message here"); 

포함하는 행을 발견하면

그러나 InvalidOperationException이 예외 :

작업이 초기화되기 전에 로그인을 시도했습니다. 메시지는 ...

어떤 제안이 있습니까? (이전에는 이러한 문제를 피하기 위해 내 사용자 정의 작업에 주로 단위 테스트를 실시했습니다.)

+1

방금 ​​내가 몇 가지 맞춤 작업에이 문제가 발생했습니다. Branstar의 대답은 정확했습니다. 호출 된 작업에서 BuildEngine을 설정하기 만하면됩니다. –

답변

24

당신은 당신이 호출하는 사용자 지정 작업의 .BuildEngine 속성을 설정해야합니다.

현재 작업이 출력을 원활하게 포함하기 위해 사용하는 것과 동일한 BuildEngine으로 설정할 수 있습니다.

Task myCustomTask = new CustomTask(); 
myCustomTask.BuildEngine = this.BuildEngine; 
myCustomTask.Execute(); 
+0

이것은 정확하게 내가 필요로했던 - 감사합니다! –

+12

질문은 단위 테스트의 컨텍스트에서 발생했기 때문에 IBuildEngine 인터페이스를 구현하는 mock/stub 개체에 BuildEngine 속성을 설정할 수도 있습니다. –

7

인터페이스 ITask를 구현 한 경우 Log 클래스를 직접 초기화해야합니다.

그렇지 않으면 당신은 작업에서 아이 태스크를 구현하고 당신을 위해 다리 많은 작업을 수행 Microsoft.Build.Utilities.dll 에서 상속해야합니다.

다음은 사용자 정의 작업을 작성하기위한 참조 페이지입니다.

Building a custom MSBuild task reference

또한 볼 가치는 당신이 당신의 사용자 지정 작업을 호출에 사용하는 MSBuild에서 XML을 게시 할 수있는 다음 다른

How to debug a custom MSBuild task

입니다. 코드 자체가 분명히 가장 도움이 될 것입니다 :-)

+0

+1 ... 좋은 링크 – alexandrul

14

작업이 msbuild에서 실행되지 않으면 로그 인스턴스가 작동하지 않기 때문에 대개 내 호출을 로그에 저장 한 다음 BuildEngine 값을 확인합니다. 내가 msbuild에서 실행 중인지 확인합니다. 아래.

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

모의/스터브에 대한 @Kiff 코멘트 IBuildEngine은 좋은 생각입니다. 여기 내 FakeBuildEngine입니다. C# 및 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 

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"; } 
    } 

} 
+3

그냥 조롱 프레임 워크를 사용해야합니다. NS substitute에서는 다음과 같습니다. var engine = Substitute.For (); –

+2

맞아요, 만약 당신이 단지'InvalidOperationException'을 피하려고한다면, 구체적인 구현이 필요 없습니다. 인스턴스가 null이 아닌 한, 당신은'InvalidOperationException'을 보지 않을 것입니다. Moq의 경우, myCustomTask.BuildEngine = new Mock (). Object;가됩니다. 적은 버그에 대한 코드 감소 : – mikegradek

+0

@perropicante True Moq가 사용될 수있었습니다. 당시에는 IBuildEngine이 필요한 많은 테스트가 있었으며 구체적인 구현은 사용하기가 쉽고 테스트를 더 쉽게 읽을 수있게 만들었습니다. –

1

나는 같은 문제가 있었다.빌드 엔진을 스터 빙하여 해결했습니다. 같은 (appSettings는이 MSBUILD 작업 이름입니다) : 조립 System.Web에서

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(); 
     } 
    } 
} 
0

System.Web.Compilationnamespace에서 팀 머피을 설명하는 방식으로 IBuildEngineinterface를 구현하는 클래스 MockEngine이다.

+0

... 잭이 지은 집에서. –

관련 문제