2008-11-04 8 views
25

मैंने कुछ एमएसबिल्ड कस्टम कार्यों को लिखा है जो अच्छी तरह से काम करते हैं और हमारे क्रूज़ कंट्रोल.नेट निर्माण प्रक्रिया में उपयोग करते हैं।यूनिट टेस्ट एमएसबिल्ड कस्टम टास्क बिना "कार्य शुरू होने से पहले लॉग करने का प्रयास किया गया" त्रुटि

मैं एक को संशोधित कर रहा हूं, और टास्क की निष्पादन() विधि को कॉल करके इकाई का परीक्षण करना चाहता हूं।

हालांकि, अगर यह

Log.LogMessage("some message here"); 

रखने वाली पंक्ति का सामना करना पड़ता है कि यह एक InvalidOperationException फेंकता है:

टास्क पहले यह प्रारंभ किया गया था लॉग इन करने का प्रयास किया। संदेश था ...

कोई सुझाव? (अतीत में मेरे पास ऐसी समस्याओं से बचने के लिए मेरे कस्टम कार्यों पर अधिकतर यूनिट-परीक्षण आंतरिक स्थैतिक विधियां हैं।)

+1

एसओ - ब्रैनस्टार के उत्तर के लिए मैंने अभी कुछ कस्टम कार्यों पर इसका सामना किया है! बस बुलाए गए कार्य पर BuildEngine सेट करें। –

उत्तर

24

आप बुला रहे हैं कस्टम कार्य के .BuildEngine संपत्ति सेट करना होगा।

आप इसे उसी बिल्डइंजिन पर सेट कर सकते हैं जो आपका वर्तमान कार्य आउटपुट को निर्बाध रूप से शामिल करने के लिए उपयोग कर रहा है।

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

यह वही था जो मुझे चाहिए - धन्यवाद! –

+12

चूंकि प्रश्न एक यूनिट टेस्ट के संदर्भ में था, इसलिए मैं यह भी जोड़ूंगा कि आप वैकल्पिक रूप से BuildEngine प्रॉपर्टी को एक नकली/स्टब ऑब्जेक्ट पर सेट कर सकते हैं जो IBuildEngine इंटरफ़ेस को लागू करता है। –

7

यदि आपने इंटरफ़ेस आईटास्क लागू किया है तो आपको लॉग क्लास को स्वयं शुरू करना होगा।

अन्यथा आप केवल से टास्क Microsoft.Build.Utilities.dll कि ITask लागू करता है और आप के लिए पैर बहुत काम करता है में वारिस चाहिए।

कस्टम कार्य बनाने के लिए संदर्भ पृष्ठ यहां दिया गया है, यह काफी कुछ बताता है।

Building a custom MSBuild task reference

इसके अलावा लायक एक नज़र है कि आप पोस्ट कर सकता MSBuild एक्सएमएल आप अपने कस्टम कार्य फोन करने के लिए उपयोग कर रहे हैं

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

@ नकली टिप्पणी mock/stub IBuildEngine पर एक अच्छा विचार है। यहाँ मेरा FakeBuildEngine है। सी # और वीबीएनईटी उदाहरण प्रदान किए गए।

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 

सी #

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

सिर्फ एक मॉकिंग फ्रेमवर्क का उपयोग करना चाहिए। NSubstitute में यह होगा: var इंजन = सबस्टिट्यूट। (); –

+2

ठीक है, अगर आप केवल 'अवैधऑपरेशन अपवाद' से बचने के लिए देख रहे हैं, तो ठोस कार्यान्वयन की कोई आवश्यकता नहीं है। जब तक इंस्टेंस शून्य नहीं होता है, तब तक आपको 'अवैधऑपरेशन अपवाद' दिखाई नहीं देगा। मोक के लिए, यह 'myCustomTask.BuildEngine = नया मॉक () ऑब्जेक्ट होगा; '। कम बग के लिए कम कोड :) – mikegradek

+0

@perropicante True Moq का उपयोग किया जा सकता था। उस समय मेरे पास कई परीक्षण थे जिनके लिए आईबीयूल्डइंजिन की आवश्यकता थी और एक ठोस कार्यान्वयन का उपयोग करना आसान था और परीक्षणों को पढ़ने में आसान बना दिया गया था। जैक द्वारा निर्मित घर में –

1

मैं एक ही समस्या थी।मैंने इसे बिल्ड इंजन को दबाकर हल किया। जैसा तो (AppSettings 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(); 
     } 
    } 
} 
0

विधानसभा System.Web में namespace में System.Web.Compilation एक वर्ग MockEngine जो एक तरह से जो टिम मर्फी का वर्णन में IBuildEngineinterface लागू करता है।

+0

...। –