c# - एंटिटी फ्रेमवर्क 6 के साथ लोग यूनिट परीक्षण कैसे करते हैं, क्या आपको परेशान होना चाहिए?




entity-framework unit-testing (7)

मैं सामान्य रूप से यूनिट टेस्टिंग और टीडीडी के साथ शुरू कर रहा हूं। मैंने पहले डब किया है लेकिन अब मैं इसे अपने वर्कफ़्लो में जोड़ने और बेहतर सॉफ़्टवेयर लिखने का दृढ़ संकल्प रखता हूं।

मैंने कल एक सवाल पूछा कि इस तरह के शामिल हैं, लेकिन ऐसा लगता है कि यह स्वयं ही एक प्रश्न है। मैं एक सेवा वर्ग को लागू करने के लिए बैठ गया हूं जिसका उपयोग मैं नियंत्रकों से व्यापार तर्क को दूर करने और ईएफ 6 का उपयोग करके विशिष्ट मॉडलों और डेटा इंटरैक्शन पर मैप करने के लिए उपयोग करूंगा।

मुद्दा यह है कि मैंने पहले से ही रोडब्लॉक किया है क्योंकि मैं एक भंडार में ईएफ को दूर करना नहीं चाहता था (यह अभी भी विशिष्ट प्रश्नों के लिए सेवाओं के बाहर उपलब्ध होगा) और मेरी सेवाओं का परीक्षण करना चाहते हैं (ईएफ संदर्भ का उपयोग किया जाएगा) ।

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

जिस कोड को मैं परीक्षण करना चाहता हूं वह बहुत आसान लगता है। (यह सिर्फ डमी कोड है और यह समझने के लिए कि मैं क्या कर रहा हूं, मैं टीडीडी का उपयोग करके सृजन को ड्राइव करना चाहता हूं)

प्रसंग

public interface IContext
{
    IDbSet<Product> Products { get; set; }
    IDbSet<Category> Categories { get; set; }
    int SaveChanges();
}

public class DataContext : DbContext, IContext
{
    public IDbSet<Product> Products { get; set; }
    public IDbSet<Category> Categories { get; set; }

    public DataContext(string connectionString)
                : base(connectionString)
    {

    }
}

सर्विस

public class ProductService : IProductService
{
    private IContext _context;

    public ProductService(IContext dbContext)
    {
        _context = dbContext;
    }

    public IEnumerable<Product> GetAll()
    {
        var query = from p in _context.Products
                    select p;

        return query;
    }
}

वर्तमान में मैं कुछ चीजें करने की मानसिकता में हूं:

  1. इस दृष्टिकोण की तरह कुछ के साथ ईएफ संदर्भ का मज़ाक उड़ाते हुए- ईएफ का मज़ाक उड़ाते समय यूनिट परीक्षण या सीधे एमक्यू जैसे इंटरफ़ेस पर एक मॉकिंग फ्रेमवर्क का उपयोग करके - यूनिट परीक्षणों को पार करने वाले दर्द को लेना, लेकिन जरूरी नहीं कि अंत तक काम खत्म हो जाए और उन्हें एकीकरण परीक्षणों के साथ वापस कर दें?
  2. शायद ईएफ को नकली करने के Effort तरह कुछ उपयोग करना - मैंने कभी इसका इस्तेमाल नहीं किया है और यह सुनिश्चित नहीं है कि कोई और जंगली में इसका उपयोग कर रहा है या नहीं?
  3. किसी भी चीज का परीक्षण करने से परेशान नहीं है जो ईएफ पर सीधे कॉल करता है - इसलिए अनिवार्य रूप से सेवा विधियां जो ईएफ को सीधे कॉल करती हैं (getAll आदि) यूनिट परीक्षण नहीं होती हैं बल्कि केवल एकीकरण का परीक्षण किया जाता है?

वास्तव में वहाँ कोई भी रेपो के बिना बाहर कर रहा है और सफलता प्राप्त कर रहा है?


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

यूनिट परीक्षण किसी फ़ंक्शन के तर्क और किसी भी बाहरी निर्भरता से अलगाव में इसके संभावित परिणामों का परीक्षण करने के बारे में है, जो इस मामले में डेटा स्टोर है। ऐसा करने के लिए, आपको डेटा स्टोर के व्यवहार को नियंत्रित करने में सक्षम होना चाहिए। उदाहरण के लिए, यदि आप यह कहना चाहते हैं कि आपका फ़ंक्शन झूठा रिटर्न देता है यदि प्राप्त उपयोगकर्ता मानदंड के कुछ सेट को पूरा नहीं करता है, तो आपके [मॉक किए गए] डेटा स्टोर को हमेशा ऐसे उपयोगकर्ता को वापस करने के लिए कॉन्फ़िगर किया जाना चाहिए जो मानदंडों को पूरा करने में विफल रहता है, और उपाध्यक्ष विपरीत दावे के विपरीत।

इसके साथ ही, और इस तथ्य को स्वीकार करते हुए कि ईएफ एक कार्यान्वयन है, मैं शायद एक भंडार सारण करने के विचार का पक्ष लेगा। थोड़ा अनावश्यक लगता है? ऐसा नहीं है, क्योंकि आप एक समस्या को हल कर रहे हैं जो डेटा कार्यान्वयन से आपके कोड को अलग कर रहा है।

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

यह थोड़ा और काम है और उनमें से कई नाक अंगूठे हैं, लेकिन यह एक असली समस्या हल करता है। एक इन-मेमोरी प्रदाता है जिसका एक अलग उत्तर में उल्लेख किया गया था जो एक विकल्प हो सकता है (मैंने इसे आजमाया नहीं है), और यह अस्तित्व है कि इस अभ्यास की आवश्यकता का सबूत सबूत है।

मैं पूरी तरह से शीर्ष जवाब से असहमत हूं क्योंकि यह वास्तविक समस्या को दूर करता है जो आपके कोड को अलग कर रहा है और फिर आपके मानचित्रण का परीक्षण करने के बारे में एक स्पर्शरेखा पर चला जाता है। यदि आप चाहते हैं तो हर तरह से अपने मानचित्रण का परीक्षण करें, लेकिन वास्तविक समस्या को यहां संबोधित करें और कुछ वास्तविक कोड कवरेज प्राप्त करें।


प्रयास अनुभव यहां प्रतिक्रिया

बहुत सारे पढ़ने के बाद मैं अपने परीक्षणों में Effort का उपयोग कर रहा हूं: परीक्षणों के दौरान संदर्भ एक कारखाने द्वारा बनाया गया है जो मेमोरी संस्करण में लौटाता है, जो मुझे हर बार एक खाली स्लेट के खिलाफ परीक्षण करने देता है। परीक्षणों के बाहर, फैक्ट्री को हल किया जाता है जो पूरे संदर्भ को लौटाता है।

हालांकि मुझे एहसास है कि डेटाबेस के पूर्ण विशेषीकृत मॉक के खिलाफ परीक्षण परीक्षण को खींचने के लिए होता है; आपको एहसास है कि सिस्टम के एक हिस्से का परीक्षण करने के लिए आपको निर्भरताओं का एक पूरा समूह स्थापित करने की देखभाल करना है। आप उन परीक्षणों को व्यवस्थित करने की ओर भी झुकाव करते हैं जो संबंधित नहीं हो सकते हैं, सिर्फ इसलिए कि केवल एक बड़ी वस्तु है जो सब कुछ संभालती है। यदि आप ध्यान नहीं देते हैं, तो आप इकाई परीक्षण के बजाए एकीकरण परीक्षण कर सकते हैं

मैं एक विशाल डीबीसीएन्टेक्स्ट की बजाय कुछ और सार के खिलाफ परीक्षण करना चाहता था लेकिन मुझे सार्थक परीक्षण और नंगे हड्डी परीक्षणों के बीच मीठा स्थान नहीं मिला। इसे अपने अनुभवहीनता के लिए चाक लें।

तो मुझे प्रयास दिलचस्प लगता है; यदि आपको जमीन पर चलने की जरूरत है तो जल्दी से शुरू करने और परिणाम प्राप्त करने के लिए यह एक अच्छा टूल है। हालांकि मुझे लगता है कि कुछ और अधिक सुरुचिपूर्ण और अमूर्त अगले कदम होना चाहिए और यही वह है जो मैं अगले जांच के लिए जा रहा हूं। यह पोस्ट देखने के लिए कि यह कहां जाता है :)

जोड़ने के लिए संपादित करें : प्रयास गर्म करने में कुछ समय लगता है, इसलिए आप लगभग देख रहे हैं। परीक्षण शुरू होने पर 5 सेकंड। यदि आपको अपने परीक्षण सूट को बहुत कुशल होने की आवश्यकता है तो यह आपके लिए एक समस्या हो सकती है।

स्पष्टीकरण के लिए संपादित किया गया:

मैंने एक webservice ऐप का परीक्षण करने के लिए प्रयास किया। प्रत्येक संदेश एम जो प्रवेश करता है उसे IHandlerOf<M> विंडसर के माध्यम से भेजा जाता है। Castle.Windsor IHandlerOf<M> हल करता है जो घटक की निर्भरताओं को दोहराता है। इन निर्भरताओं में से एक DataContextFactory , जो हैंडलर को कारखाने के लिए पूछने देता है

मेरे परीक्षणों में मैं सीधे IHandlerOf घटक को तुरंत चालू करता हूं, SUT के सभी उप-घटकों को नकल करता हूं और हैंडलर पर प्रयास-लपेटा डेटाकॉन्टेक्स्ट फैक्ट्री को संभालता है।

इसका मतलब है कि मैं सख्त अर्थ में इकाई परीक्षण नहीं करता, क्योंकि डीबी मेरे परीक्षणों से मारा जाता है। हालांकि जैसा कि मैंने उपरोक्त कहा है, मुझे जमीन पर चलने दें और मैं आवेदन में कुछ बिंदुओं का त्वरित परीक्षण कर सकता हूं


मैं यूनिट टेस्ट कोड नहीं रखूंगा जिसका मेरा स्वामित्व नहीं है। आप यहां क्या परीक्षण कर रहे हैं, कि एमएसएफटी कंपाइलर काम करता है?

उस ने कहा, इस कोड को टेस्ट करने योग्य बनाने के लिए, आपको लगभग अपने डेटा लॉजिक कोड से अलग डेटा एक्सेस लेयर बनाना होगा। मैं जो करता हूं वह मेरी सभी ईएफ सामग्री लेता है और इसे एक (या एकाधिक) डीएओ या डीएएल कक्षा में डालता है जिसमें एक समान इंटरफ़ेस भी होता है। फिर मैं अपनी सेवा लिखता हूं जिसमें डीएओ या डीएएल ऑब्जेक्ट को इंटरफेस के रूप में संदर्भित निर्भरता (कन्स्ट्रक्टर इंजेक्शन अधिमानतः) के रूप में इंजेक्शन दिया जाएगा। अब जिस भाग को परीक्षण करने की आवश्यकता है (आपका कोड) आसानी से डीएओ इंटरफ़ेस का मज़ाक उड़ाकर और आपके यूनिट परीक्षण के अंदर आपके सेवा उदाहरण में इंजेक्शन करके परीक्षण किया जा सकता है।

//this is testable just inject a mock of IProductDAO during unit testing
public class ProductService : IProductService
{
    private IProductDAO _productDAO;

    public ProductService(IProductDAO productDAO)
    {
        _productDAO = productDAO;
    }

    public List<Product> GetAllProducts()
    {
        return _productDAO.GetAll();
    }

    ...
}

मैं एकीकरण परीक्षण का हिस्सा बनने के लिए लाइव डेटा एक्सेस परतों पर विचार करता हूं, यूनिट परीक्षण नहीं। मैंने लोगों को यह सत्यापित किया है कि डेटाबेस हाइबरनेट के कितने भ्रमण पहले होते हैं, लेकिन वे एक ऐसे प्रोजेक्ट पर थे जिसमें उनके डेटास्टोर में अरबों रिकॉर्ड शामिल थे और उन अतिरिक्त यात्राओं वास्तव में महत्वपूर्ण थीं।


मैंने इन विचारों तक पहुंचने के लिए कभी-कभी झुका दिया है:

1- यदि मेरा एप्लिकेशन डेटाबेस तक पहुंचता है, तो परीक्षण क्यों नहीं होना चाहिए? डेटा पहुंच के साथ कुछ गलत होने पर क्या होगा? परीक्षणों को पहले से ही पता होना चाहिए और समस्या के बारे में खुद को सतर्क करना चाहिए।

2- रिपोजिटरी पैटर्न कुछ हद तक कठिन और समय लेने वाला है।

तो मैं इस दृष्टिकोण के साथ आया, कि मुझे नहीं लगता कि सबसे अच्छा है, लेकिन मेरी उम्मीदों को पूरा किया:

Use TransactionScope in the tests methods to avoid changes in the database.

ऐसा करने के लिए यह आवश्यक है:

1- परीक्षण परियोजना में EntityFramework स्थापित करें। 2- कनेक्शन स्ट्रिंग को ऐप.कॉन्फिग फ़ाइल में टेस्ट प्रोजेक्ट में रखें। 3- डीएल सिस्टम का संदर्भ लें। टेस्ट प्रोजेक्ट में लेनदेन।

अद्वितीय साइड इफेक्ट यह है कि लेनदेन रद्द होने पर भी, सम्मिलित करने की कोशिश करते समय पहचान बीज बढ़ेगा। लेकिन चूंकि परीक्षण डेटाबेस के खिलाफ परीक्षण किए जाते हैं, इसलिए यह कोई समस्या नहीं होनी चाहिए।

नमूना कोड:

[TestClass]
public class NameValueTest
{
    [TestMethod]
    public void Edit()
    {
        NameValueController controller = new NameValueController();

        using(var ts = new TransactionScope()) {
            Assert.IsNotNull(controller.Edit(new Models.NameValue()
            {
                NameValueId = 1,
                name1 = "1",
                name2 = "2",
                name3 = "3",
                name4 = "4"
            }));

            //no complete, automatically abort
            //ts.Complete();
        }
    }

    [TestMethod]
    public void Create()
    {
        NameValueController controller = new NameValueController();

        using (var ts = new TransactionScope())
        {
            Assert.IsNotNull(controller.Create(new Models.NameValue()
            {
                name1 = "1",
                name2 = "2",
                name3 = "3",
                name4 = "4"
            }));

            //no complete, automatically abort
            //ts.Complete();
        }
    }
}

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

हालांकि, आप नीचे डेटाबेस का मालिक है! यह वह जगह है जहां मेरी राय में यह दृष्टिकोण टूट जाता है, आपको यह जांचने की आवश्यकता नहीं है कि ईएफ / एनएच अपनी नौकरी सही तरीके से कर रहे हैं। आपको यह जांचने की ज़रूरत है कि आपके मैपिंग / कार्यान्वयन आपके डेटाबेस के साथ काम कर रहे हैं। मेरी राय में यह एक प्रणाली के सबसे महत्वपूर्ण भागों में से एक है जिसे आप परीक्षण कर सकते हैं।

कड़ाई से बोलते हुए हम यूनिट परीक्षण के डोमेन से बाहर निकल रहे हैं और एकीकरण परीक्षण में हैं लेकिन प्रिंसिपल वही रहते हैं।

आपको सबसे पहले जो करना है वह है अपने डीएएल को नकल करने में सक्षम होना ताकि आपका बीएलएल स्वतंत्र रूप से ईएफ और एसक्यूएल का परीक्षण किया जा सके। ये आपके यूनिट परीक्षण हैं। इसके बाद आपको अपने डीएएल को साबित करने के लिए अपने एकीकरण टेस्ट को डिजाइन करने की आवश्यकता है, मेरी राय में ये हर महत्वपूर्ण हैं।

विचार करने के लिए कुछ चीजें हैं:

  1. आपके डेटाबेस को प्रत्येक परीक्षण के साथ एक ज्ञात राज्य में होना चाहिए। अधिकांश सिस्टम बैकअप का उपयोग करते हैं या इसके लिए स्क्रिप्ट बनाते हैं।
  2. प्रत्येक परीक्षण दोहराने योग्य होना चाहिए
  3. प्रत्येक परीक्षण परमाणु होना चाहिए

अपने डेटाबेस को स्थापित करने के लिए दो मुख्य दृष्टिकोण हैं, पहला यूनिटटेस्ट डीबी स्क्रिप्ट बनाने के लिए है। यह सुनिश्चित करता है कि प्रत्येक इकाई की शुरुआत में आपका यूनिट टेस्ट डेटाबेस हमेशा एक ही स्थिति में होगा (आप या तो इसे रीसेट कर सकते हैं या यह सुनिश्चित करने के लिए प्रत्येक परीक्षण को लेनदेन में चला सकते हैं)।

आपका दूसरा विकल्प मैं करता हूं, प्रत्येक व्यक्तिगत परीक्षण के लिए विशिष्ट सेटअप चलाएं। मेरा मानना ​​है कि यह दो मुख्य कारणों के लिए सबसे अच्छा तरीका है:

  • आपका डेटाबेस सरल है, आपको प्रत्येक परीक्षण के लिए पूरी स्कीमा की आवश्यकता नहीं है
  • प्रत्येक परीक्षण सुरक्षित है, यदि आप अपनी निर्माण स्क्रिप्ट में एक मान बदलते हैं तो यह कई अन्य परीक्षणों को अमान्य नहीं करता है।

दुर्भाग्यवश यहां आपका समझौता गति है। इन सभी परीक्षणों को चलाने के लिए इन सभी परीक्षणों को चलाने में समय लगता है / स्क्रिप्ट को फाड़ें।

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

यह आदर्श समाधान से बहुत दूर है हालांकि अभ्यास में मुझे लगता है कि यह प्रबंधित करने में बहुत आसान है (विशेष रूप से जब आपके पास कई हजार परीक्षण होते हैं), अन्यथा आप बड़ी संख्या में स्क्रिप्ट बना रहे हैं। शुद्धता पर व्यावहारिकता।

मुझे कुछ वर्षों (महीनों / दिनों) में इस जवाब पर कोई संदेह नहीं होगा और मेरे दृष्टिकोण से बदलकर मेरे साथ असहमत होगा - हालांकि यह मेरा वर्तमान दृष्टिकोण है।

मैंने जो कुछ भी कहा है, उसे आजमाने और समेटने के लिए यह मेरा सामान्य डीबी एकीकरण परीक्षण है:

[Test]
public void LoadUser()
{
  this.RunTest(session => // the NH/EF session to attach the objects to
  {
    var user = new UserAccount("Mr", "Joe", "Bloggs");
    session.Save(user);
    return user.UserID;
  }, id => // the ID of the entity we need to load
  {
     var user = LoadMyUser(id); // load the entity
     Assert.AreEqual("Mr", user.Title); // test your properties
     Assert.AreEqual("Joe", user.Firstname);
     Assert.AreEqual("Bloggs", user.Lastname);
  }
}

यहां ध्यान देने योग्य महत्वपूर्ण बात ये है कि दो लूप के सत्र पूरी तरह से स्वतंत्र हैं। RunTest के कार्यान्वयन में आपको यह सुनिश्चित करना होगा कि संदर्भ प्रतिबद्ध और नष्ट हो गया है और आपका डेटा केवल दूसरे भाग के लिए आपके डेटाबेस से आ सकता है।

13/10/2014 संपादित करें

मैंने कहा था कि मैं शायद आने वाले महीनों में इस मॉडल को संशोधित करूंगा। जबकि मैं काफी हद तक दृष्टिकोण से खड़ा हूं, मैंने उपरोक्त वकालत की है, मैंने अपने परीक्षण तंत्र को थोड़ा अद्यतन किया है। अब मैं टेस्टसेटअप और टेस्टटायरडाउन में इकाइयों को बनाने की कोशिश करता हूं।

[SetUp]
public void Setup()
{
  this.SetupTest(session => // the NH/EF session to attach the objects to
  {
    var user = new UserAccount("Mr", "Joe", "Bloggs");
    session.Save(user);
    this.UserID =  user.UserID;
  });
}

[TearDown]
public void TearDown()
{
   this.TearDownDatabase();
}

फिर व्यक्तिगत रूप से प्रत्येक संपत्ति का परीक्षण करें

[Test]
public void TestTitle()
{
     var user = LoadMyUser(this.UserID); // load the entity
     Assert.AreEqual("Mr", user.Title);
}

[Test]
public void TestFirstname()
{
     var user = LoadMyUser(this.UserID);
     Assert.AreEqual("Joe", user.Firstname);
}

[Test]
public void TestLastname()
{
     var user = LoadMyUser(this.UserID);
     Assert.AreEqual("Bloggs", user.Lastname);
}

इस दृष्टिकोण के कई कारण हैं:

  • कोई अतिरिक्त डेटाबेस कॉल नहीं है (एक सेटअप, एक टियरडाउन)
  • परीक्षण बहुत अधिक दानेदार होते हैं, प्रत्येक परीक्षण एक संपत्ति की पुष्टि करता है
  • टेस्ट विधियों से सेटअप / टियरडाउन तर्क हटा दिया जाता है

मुझे लगता है कि यह टेस्ट क्लास को सरल बनाता है और परीक्षण अधिक बारीक ( एकल आवेषण अच्छे होते हैं )

5/3/2015 संपादित करें

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

इसके साथ में मदद करने के लिए अब दो बेस क्लास SetupPerTest और SingleSetup । ये दो वर्ग आवश्यकतानुसार ढांचे का पर्दाफाश करते हैं।

SingleSetup हमारे पहले संपादन में वर्णित एक बहुत ही समान तंत्र है। एक उदाहरण होगा

public TestProperties : SingleSetup
{
  public int UserID {get;set;}

  public override DoSetup(ISession session)
  {
    var user = new User("Joe", "Bloggs");
    session.Save(user);
    this.UserID = user.UserID;
  }

  [Test]
  public void TestLastname()
  {
     var user = LoadMyUser(this.UserID); // load the entity
     Assert.AreEqual("Bloggs", user.Lastname);
  }

  [Test]
  public void TestFirstname()
  {
       var user = LoadMyUser(this.UserID);
       Assert.AreEqual("Joe", user.Firstname);
  }
}

हालांकि संदर्भ जो सुनिश्चित करते हैं कि केवल सही प्रविष्टियां लोड की गई हैं, एक सेटअपअपटेस्ट दृष्टिकोण का उपयोग कर सकती हैं

public TestProperties : SetupPerTest
{
   [Test]
   public void EnsureCorrectReferenceIsLoaded()
   {
      int friendID = 0;
      this.RunTest(session =>
      {
         var user = CreateUserWithFriend();
         session.Save(user);
         friendID = user.Friends.Single().FriendID;
      } () =>
      {
         var user = GetUser();
         Assert.AreEqual(friendID, user.Friends.Single().FriendID);
      });
   }
   [Test]
   public void EnsureOnlyCorrectFriendsAreLoaded()
   {
      int userID = 0;
      this.RunTest(session =>
      {
         var user = CreateUserWithFriends(2);
         var user2 = CreateUserWithFriends(5);
         session.Save(user);
         session.Save(user2);
         userID = user.UserID;
      } () =>
      {
         var user = GetUser(userID);
         Assert.AreEqual(2, user.Friends.Count());
      });
   }
}

संक्षेप में दोनों दृष्टिकोण आप जो परीक्षण करने की कोशिश कर रहे हैं उसके आधार पर काम करते हैं।


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


There is Effort which is an in memory entity framework database provider. I've not actually tried it... Haa just spotted this was mentioned in the question!

Alternatively you could switch to EntityFrameworkCore which has an in memory database provider built-in.

https://blog.goyello.com/2016/07/14/save-time-mocking-use-your-real-entity-framework-dbcontext-in-unit-tests/

https://github.com/tamasflamich/effort

I used a factory to get a context, so i can create the context close to its use. This seems to work locally in visual studio but not on my TeamCity build server, not sure why yet.

return new MyContext(@"Server=(localdb)\mssqllocaldb;Database=EFProviders.InMemory;Trusted_Connection=True;");




entity-framework-6.1