2012-08-15 15 views
22

फेंकना मेरे पास यह जांचने के लिए निम्न कोड है कि जब मेरी विधि पर एक निश्चित नाम पारित किया जाता है, तो यह एक SQL अपवाद फेंकता है (उसमें कारण है, हालांकि यह थोड़ा अजीब लगता है)।Moq और एक SqlException

mockAccountDAL.Setup(m => m.CreateAccount(It.IsAny<string>(), 
"Display Name 2", It.IsAny<string>())).Throws<SqlException>(); 

बहरहाल, यह संकलन नहीं करेगा क्योंकि SqlException के निर्माता आंतरिक है:

'System.Data.SqlClient.SqlException' क्रम में एक सार्वजनिक parameterless निर्माता के साथ एक गैर सार प्रकार होना चाहिए अब सामान्य प्रकार या विधि 'Moq.Language.IThrows.Throws()'

में पैरामीटर के रूप में इसका इस्तेमाल करने के 'TException', मैं राज्य के लिए यह है कि इस को बदल सकता है Exception फेंकना चाहिए, लेकिन यह मेरे लिए काम नहीं करेगा, क्योंकि मेरी विधि एक स्थिति कोड वापस करनी चाहिए यदि यह SqlException है और दूसरा यदि यह कोई अन्य अपवाद है। यही मेरा यूनिट परीक्षण परीक्षण कर रहा है।

क्या मैं इस विधि का परीक्षण नहीं कर रहा हूं, या जिस विधि का परीक्षण कर रहा हूं, उसके तर्क को बदलने के बिना इसे हासिल करने का कोई तरीका है?

+1

संभावित डुप्लिकेट [एसक्लएक्सप्शन को कैसे फेंकना है (मॉकिंग की आवश्यकता है)] (http://stackoverflow.com/questions/1386962/how-to-throw-a-sqlexceptionneed-for-mocking) –

+1

आप प्रतिबिंब का उपयोग कर सकते हैं आंतरिक विधि CreateException तक पहुंचें जो आपको एक SQLException बनाने देता है। http://stackoverflow.com/questions/1259222/how-to-access-internal-class-using-reflection .... http://msdn.microsoft.com/en-us/library/ms229394(v=vs .100) .aspx ... तो बस इसे बनाने और फेंकने के लिए एक लामाडा करें। –

उत्तर

33

यह काम करना चाहिए:

using System.Runtime.Serialization; 

var exception = FormatterServices.GetUninitializedObject(typeof(SqlException)) 
       as SqlException; 

mockAccountDAL.Setup(m => m.CreateAccount(It.IsAny<string>(), "Display Name 2", 
        It.IsAny<string>())).Throws(exception); 

हालांकि, GetUninitializedObject का उपयोग कर इस चेतावनी है:

क्योंकि वस्तु का नया उदाहरण शून्य करने के लिए आरंभ नहीं हो जाता और कोई कंस्ट्रक्टर्स चलाए जा रहे हैं, वस्तु हो सकता है उस स्थिति का प्रतिनिधित्व न करें जो है जिसे उस ऑब्जेक्ट द्वारा मान्य माना जाता है।

यह किसी भी समस्याओं का कारण बनता, तो आप शायद यह कुछ और अधिक शामिल प्रतिबिंब जादू का उपयोग कर बना सकते हैं, लेकिन इस तरह से शायद सबसे सरल (अगर यह काम करता है) है।

+0

अपवाद संदेश सेट करने का कोई तरीका नहीं होगा, क्या वहां होगा? – bump

+0

@bump यह प्रतिबिंब के माध्यम से संभव हो सकता है लेकिन अंतर्निहित संरचना के आधार पर यह करना मुश्किल हो सकता है (यानी गुणों का बैकिंग फ़ील्ड प्राप्त करना और उन्हें सेट करना)। मुझे यकीन नहीं है कि संदेश आपको कौन सा सेटिंग देता है, जब तक आपके पास अपवाद संदेश कहने के आधार पर अलग-अलग तर्क नहीं चलते हैं और आपको इसका परीक्षण करने की आवश्यकता होती है। – docmanhattan

+0

मुझे वास्तव में इसका परीक्षण करने की आवश्यकता है।प्रतिबिंब (और निजी कन्स्ट्रक्टर) के माध्यम से ऐसा करने में सक्षम था। धन्यवाद। – bump

5

मैं सिर्फ यह पता करने की कोशिश की, और यह मेरे लिए काम किया:

private static void ThrowSqlException() 
{ 
    using (var cxn = new SqlConnection("Connection Timeout=1")) 
    { 
     cxn.Open(); 
    } 
} 

// ... 
mockAccountDAL.Setup(m => m.CreateAccount(It.IsAny<string>), 
        "Display Name 2", It.IsAny<string>())) 
       .Callback(() => ThrowSqlException()); 
+0

क्या होगा यदि 'CreateAccount' शून्य लौटाता है? –

+1

शायद किसी भी मामले में 'कलकबैक' का उपयोग करना चाहते हैं, अब मैं इसके बारे में सोचता हूं। उत्तर अपडेट कर रहा है। –

30

आप अपवाद के Number या Message संपत्तियों के लिए परीक्षण मामलों की जरूरत है, तो आप एक बिल्डर इस तरह (जो प्रतिबिंब का उपयोग करता है) इस्तेमाल कर सकते हैं :

using System; 
using System.Data.SqlClient; 
using System.Reflection; 

public class SqlExceptionBuilder 
{ 
    private int errorNumber; 
    private string errorMessage; 

    public SqlException Build() 
    { 
     SqlError error = this.CreateError(); 
     SqlErrorCollection errorCollection = this.CreateErrorCollection(error); 
     SqlException exception = this.CreateException(errorCollection); 

     return exception; 
    } 

    public SqlExceptionBuilder WithErrorNumber(int number) 
    { 
     this.errorNumber = number; 
     return this; 
    } 

    public SqlExceptionBuilder WithErrorMessage(string message) 
    { 
     this.errorMessage = message; 
     return this; 
    } 

    private SqlError CreateError() 
    { 
     // Create instance via reflection... 
     var ctors = typeof(SqlError).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance); 
     var firstSqlErrorCtor = ctors.FirstOrDefault(
      ctor => 
      ctor.GetParameters().Count() == 7); // Need a specific constructor! 
     SqlError error = firstSqlErrorCtor.Invoke(
      new object[] 
      { 
       this.errorNumber, 
       new byte(), 
       new byte(), 
       string.Empty, 
       string.Empty, 
       string.Empty, 
       new int() 
      }) as SqlError; 

     return error; 
    } 

    private SqlErrorCollection CreateErrorCollection(SqlError error) 
    { 
     // Create instance via reflection... 
     var sqlErrorCollectionCtor = typeof(SqlErrorCollection).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]; 
     SqlErrorCollection errorCollection = sqlErrorCollectionCtor.Invoke(new object[] { }) as SqlErrorCollection; 

     // Add error... 
     typeof(SqlErrorCollection).GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(errorCollection, new object[] { error }); 

     return errorCollection; 
    } 

    private SqlException CreateException(SqlErrorCollection errorCollection) 
    { 
     // Create instance via reflection... 
     var ctor = typeof(SqlException).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]; 
     SqlException sqlException = ctor.Invoke(
      new object[] 
      { 
       // With message and error collection... 
       this.errorMessage, 
       errorCollection, 
       null, 
       Guid.NewGuid() 
      }) as SqlException; 

     return sqlException; 
    } 
} 

तो फिर तुम भंडार नकली (उदाहरण के लिए) हो सकता है इस तरह एक अपवाद फेंक:

using Moq; 

var sqlException = 
    new SqlExceptionBuilder().WithErrorNumber(50000) 
     .WithErrorMessage("Database exception occured...") 
     .Build(); 
var repoStub = new Mock<IRepository<Product>>(); // Or whatever... 
repoStub.Setup(stub => stub.GetById(1)) 
    .Throws(sqlException); 
+1

इसके लिए धन्यवाद !! : डी –

+0

@StephanRyer मेरे पास कोड था ... बस सोचा कि मैं – bump

+1

साझा करूंगा आप एक सज्जन और विद्वान हैं। आपको इसे गिटूब पर प्राप्त करने की ज़रूरत है ताकि मैं इसे तारांकित कर सकूं। –