2015-09-13 10 views
7

मैं यूनिट परीक्षण में मॉकिंग की भावना बनाने और अपनी परियोजना में यूनिट परीक्षण प्रक्रिया को एकीकृत करने की कोशिश कर रहा हूं। इसलिए मैं कई ट्यूटोरियल्स के माध्यम से चल रहा हूं और मैकिंग का समर्थन करने के लिए अपने कोड को दोबारा कर रहा हूं, वैसे भी, मैं परीक्षण पास करने में असमर्थ हूं, क्योंकि डीबी विधि जो मैं परीक्षण करने की कोशिश कर रहा हूं वह लेनदेन का उपयोग कर रहा है, लेकिन लेनदेन बनाते समय मुझेपिछले इकाई ढांचे को प्राप्त करना BeginTransaction

मिलता है

अंतर्निहित प्रदाता ओपन पर विफल रहा।

लेनदेन के बिना सबकुछ ठीक काम करता है।

कोड मैं वर्तमान में है: परीक्षण के अंतर्गत

[TestMethod] 
public void Test1() 
{ 
    var mockSet = GetDbMock(); 
    var mockContext = new Mock<DataContext>(); 
    mockContext.Setup(m => m.Repository).Returns(mockSet.Object); 

    var service = new MyService(mockContext.Object); 
    service.SaveRepository(GetRepositoryData().First()); 
    mockSet.Verify(m => m.Remove(It.IsAny<Repository>()), Times.Once()); 
    mockSet.Verify(m => m.Add(It.IsAny<Repository>()), Times.Once()); 
    mockContext.Verify(m => m.SaveChanges(), Times.Once()); 
} 

// gets the DbSet mock with one existing item 
private Mock<DbSet<Repository>> GetDbMock() 
{ 
    var data = GetRepositoryData(); 
    var mockSet = new Mock<DbSet<Repository>>(); 

    mockSet.As<IQueryable<Repository>>().Setup(m => m.Provider).Returns(data.Provider); 
    // skipped for brevity 
    return mockSet; 
} 

कोड:

private readonly DataContext _context; 
public MyService(DataContext ctx) 
{ 
    _context = ctx; 
} 

public void SaveRepositories(Repository repo) 
{ 
    using (_context) 
    { 
     // Here the transaction creation fails 
     using (var transaction = _context.Database.BeginTransaction()) 
     { 
      DeleteExistingEntries(repo.Id); 
      AddRepositories(repo); 
      _context.SaveChanges(); 
      transaction.Commit(); 
     } 
    } 
} 

मैं लेनदेन हिस्सा उपहास करने के लिए और साथ ही कोशिश कर रहा था:

var mockTransaction = new Mock<DbContextTransaction>(); 
mockContext.Setup(x => x.Database.BeginTransaction()).Returns(mockTransaction.Object); 

लेकिन यह है काम नहीं कर रहा है, इसमें असफल रहा:

पर एक गैर आभासी (VB में overridable) सदस्य अमान्य स्थापना: Conn => conn.Database.BeginTransaction()

कोई भी विचार कैसे इस को हल करने के?

उत्तर

5

जैसा कि दूसरा त्रुटि संदेश कहता है, Moq गैर वर्चुअल विधियों या गुणों का नकल नहीं कर सकता है, इसलिए यह दृष्टिकोण काम नहीं करेगा। मैं इस पर काम करने के लिए Adapter pattern का उपयोग करने का सुझाव देता हूं। विचार एडाप्टर (एक रैपर वर्ग जो कुछ इंटरफ़ेस लागू करता है) बनाने के लिए है जो DataContext के साथ इंटरैक्ट करता है, और उस इंटरफ़ेस के माध्यम से सभी डेटाबेस गतिविधि निष्पादित करता है। फिर, आप इसके बजाय इंटरफेस का नकल कर सकते हैं।

public interface IDataContext { 
    DbSet<Repository> Repository { get; } 
    DbContextTransaction BeginTransaction(); 
} 

public class DataContextAdapter { 
    private readonly DataContext _dataContext; 

    public DataContextAdapter(DataContext dataContext) { 
     _dataContext = dataContext; 
    } 

    public DbSet<Repository> Repository { get { return _dataContext.Repository; } } 

    public DbContextTransaction BeginTransaction() { 
     return _dataContext.Database.BeginTransaction(); 
    } 
} 

अपने कोड है कि पहले DataContext इस्तेमाल किया सीधे अब एक IDataContext है, जो एक DataContextAdapter होना चाहिए जब कार्यक्रम चल रहा है का उपयोग करना चाहिए, लेकिन एक परीक्षण में, आप आसानी से IDataContext नकली कर सकते हैं सब के सब। यह मजाकिया तरीका भी आसान बनाना चाहिए क्योंकि आप वास्तविक DataContext की कुछ जटिलताओं को छिपाने के लिए IDataContext और DataContextAdapter डिज़ाइन कर सकते हैं।

+0

यह डिज़ाइन पैटर्न समझ में आता है और मैं इसे समझने के लिए आगे बढ़ूंगा। हालांकि मैं अभी भी इसे काम नहीं कर सकता क्योंकि मैं 'डीबीकॉन्टेक्स्ट ट्रांज़ेक्शन 'का नकल नहीं कर सकता क्योंकि इसमें केवल आंतरिक कन्स्ट्रक्टर है, जो कि' मोक 'की समस्या है। वैसे भी, यह पहचाना जाता है कि परीक्षण निष्पादन वास्तव में काम करने पर निर्भर नहीं है और यदि मैं डिबगिंग के बिना परीक्षण चलाता हूं, तो वे तब तक पास नहीं होते जब तक कि मैं स्पष्ट रूप से जांच नहीं करता कि क्या कोई अपवाद फेंक दिया गया है। जो अच्छा है। अंतर्दृष्टि के लिए धन्यवाद, जब तक कुछ बेहतर नहीं होता तब तक मैं इसे स्वीकार करूंगा। (Y) –

+0

आप एक ही चाल वहाँ खींच सकते हैं - अपने परीक्षण में और नकली 'IDbContextTransaction' - एक' IDbContextTransaction' इंटरफ़ेस है कि 'DbContextTransactionAdapter' है, जो एक वास्तविक' DbContextTransaction' लपेटता द्वारा कार्यान्वित किया जाता पैदा करते हैं। यह थोड़ा परेशानी है, लेकिन यह चाल आमतौर पर कोड बनाती है जो लाइब्रेरी कोड का परीक्षण करने के लिए बहुत आसान होती है, और लाइब्रेरी के साथ कम कसकर मिलती है। –

+0

जब मैंने मॉक किया था तो हाल ही में एक चीज ने मुझे आश्चर्यचकित कर दिया। से यह है कि नकली की डेटाबेस संपत्ति app.config में कनेक्शन जानकारी का उपयोग कर एक ठोस डेटाबेस ऑब्जेक्ट बनाती है। तो कोई डेटाबेस.एक्सक्यूट एसक्यूएल संभावित रूप से उस डेटाबेस के खिलाफ चलाएगा। BeginTransaction से एक ठोस लेनदेन भी वापस कर दिया।ऐसा कैसे होता है, कि एक नकली असली चीज़ देता है? –

संबंधित मुद्दे