2008-11-04 14 views
25

CruiseControl.NET oluşturma işlemimizde iyi çalışan ve iyi çalışan birkaç MSBuild özel görevi yazdım.Birim sınaması MSBuild "Görev başlatılmadan önce günlüğe kaydetme girişiminde bulunulmadı" hatası

Bir tanesini değiştiriyorum ve Task'ın Execute() yöntemini çağırarak birimi sınamak istiyorum. o

Log.LogMessage("some message here"); 

içeren bir satır karşılaşırsa

Ancak, bir InvalidOperationException atar:

Görev o başlatıldı önce oturum çalıştı. İleti ...

Herhangi bir öneriniz var mı? (Geçmişte çoğunlukla bu tür sorunları önlemek için özel görevlerimde birim tarafından sınanmış olan iç statik yöntemler var.)

+1

Şimdilik bunu SO için bazı özel görevlerde gördüm - Branstar'ın cevabı doğruydu! Sadece çağrılan görev üzerinde BuildEngine ayarlayın. –

cevap

24

Sen aradığınız özel görevin .BuildEngine özelliğini ayarlamanız gerekir.

Geçerli görevinizin çıktısını sorunsuz bir şekilde eklemek için kullandığınız BuildEngine ile aynı şekilde ayarlayabilirsiniz.

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

Tam olarak ihtiyacım olan şey buydu - teşekkürler! –

+12

Soru bir birim testi bağlamında olduğundan, alternatif olarak BuildEngine özelliğini, IBuildEngine arabirimini uygulayan bir sahte/saplama nesnesine ayarlayabileceğinizi de eklerim. –

7

ITask arabirimini uyguladıysanız, Log sınıfını kendiniz başlatmanız gerekecektir.

Aksi takdirde sadece Görevden ITaskuygular ve sizin için bacak çok iş yapar Microsoft.Build.Utilities.dll içinde alması gerektiğini.

Özel bir görev oluşturmak için başvuru sayfası aşağıda açıklanmıştır.

Building a custom MSBuild task reference

Ayrıca bir göz değer size özel bir görev çağırmak için kullandığınız MSBuild XML sonrası olabilir Sonra diğer

How to debug a custom MSBuild task

olduğunu. Kodun kendisi açıkça en çok yardımcı olacaktır :-)

+0

+1 ... nice linkler – alexandrul

14

Görev örneğinin msbuild içinde çalışmadığı sürece günlük örneğinin çalışmadığını fark ettim, bu yüzden aramalarımı Log'a yazdım, sonra BuildEngine değerini kontrol et msbuild içinde çalışıp çalışmadığımı belirlemek için. Aşağıda olduğu gibi.

Tim

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

@Kick'e yorum/ankastre IBuildEngine iyi bir fikirdir. İşte benim FakeBuildEngine. C# ve VB.NET örnekleri sağladı.

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

Sadece alaycı bir çerçeve kullanmalıdır. NSubstitute'de şu olabilir: var engine = Değiştirme. (); –

+2

Doğru, yalnızca InvalidOperationException'dan kaçınmayı düşünüyorsanız, somut bir uygulamaya gerek yoktur. Örnek boş olmadığı sürece, 'InvalidOperationException' görmezsiniz. Moq için 'myCustomTask.BuildEngine = new Mock (). Object; 'olacaktır. Daha az hata için daha az kod :) – mikegradek

+0

@perropicante True Moq kullanılmış olabilir. O zamanlar IBuildEngine'e ihtiyaç duyulan birçok testim vardı ve somut bir uygulamanın kullanılması daha kolaydı ve testleri daha kolay okumuştur. –

1

ben aynı problem vardı.Yapı motorunu kovalı olarak çözdüm. Gibi öylesine (AppSettings'i MsBuild Görev Name is): montaj System.Web yılında

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 Tim Murphy açıklayacak şekilde IBuildEngineinterface uygulayan bir sınıf MockEngine olduğunu.

+0

... Jack'in inşa ettiği evde. –

İlgili konular