2016-11-09 12 views
6

पर अद्वितीय_ptr के साथ निर्भरता इंजेक्शन मेरे पास कक्षा बार का उपयोग करने वाला क्लास फू है। बार (एक संदर्भ नहीं है, क्योंकि मैं फू के बाहर बार जरूरत नहीं है) केवल फू में प्रयोग किया जाता है और फू प्रबंध बार है, इसलिए मैं unique_ptr का उपयोग करें:नकली

using namespace std; 
struct IBar { 
    virtual ~IBar() = default; 
    virtual void DoSth() = 0; 
}; 

struct Bar : public IBar { 
    void DoSth() override { cout <<"Bar is doing sth" << endl;};  
}; 

struct Foo { 
    Foo(unique_ptr<IBar> bar) : bar_(std::move(bar)) {} 

    void DoIt() { 
    bar_->DoSth(); 
    } 
private: 
    unique_ptr<IBar> bar_; 
}; 

अब तक तो अच्छा, यह ठीक काम करता है।

namespace { 
struct BarMock : public IBar { 
    MOCK_METHOD0(DoSth, void()); 
}; 
} 

struct FooTest : public Test { 
    FooTest() : barMock{ make_unique<BarMock>() }, out(std::move(barMock)) {} 

    unique_ptr<BarMock> barMock; 
    Foo out; 
}; 

TEST_F(FooTest, shouldDoItWhenDoSth) { 
    EXPECT_CALL(*barMock, DoSth()); 

    out.DoIt(); 
} 

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

डि के संभावित विकल्प:

  • shared_ptr द्वारा: एक विकल्प (नहीं है: इस मामले में बहुत ज्यादा (बार वस्तु फू के बीच किसी और किसी भी कुछ भी साझा नहीं है)
  • Ibar के संदर्भ द्वारा है बार को फू के बाहर संग्रहीत नहीं किया जाता है, इसलिए बनाए गए बार ऑब्जेक्ट को फू को संदर्भित करने के साथ छोड़ दिया जाएगा)
  • अद्वितीय_ptr द्वारा: प्रस्तुत किए गए तरीके से
  • मूल्य से गुज़रने से परीक्षण योग्य नहीं है: संभव नहीं है (प्रतिलिपि बनाना मौका - unique_ptr के साथ एक ही मुद्दा)।

एकमात्र समाधान मुझे मिल फू से पहले BarMock के लिए कच्चे सूचक की दुकान, केवल BarMock के मालिक बनने के लिए है यानी .:

struct FooTest : public Test { 
    FooTest() : barMock{new BarMock} { 
    auto ptr = unique_ptr<BarMock>(barMock); 
    out.reset(new Foo(std::move(ptr))); 
    } 

    BarMock* barMock; 
    unique_ptr<Foo> out; 
}; 

वहाँ एक क्लीनर समाधान नहीं है? क्या मुझे स्थिर निर्भरता इंजेक्शन (टेम्पलेट्स) का उपयोग करना है? कुछ

+2

की खिन्न) आप पढ़ने में [इस उत्तर] (http://stackoverflow.com/questions/7616475/can-google-mock-a-method-with-a-smart-pointer दिलचस्पी हो सकती है -return प्रकार/11548191 # 11548191)। –

+0

@ πάντα ῥεῖ: लिंक के लिए धन्यवाद। मैंने इसे पहले ही देखा है और यह उन विधियों के लिए काम करता है जो पैरामीटर के रूप में unique_ptr लेते हैं - लेकिन मुझे यकीन नहीं है कि कोई भी रचनाकारों के लिए इस दृष्टिकोण को लागू कर सकता है। – Quarra

उत्तर

2

नहीं मैं उत्पादन वातावरण में वास्तव में की सिफारिश करेंगे, लेकिन अलियासिंग निर्माता shared_ptr की हो सकता है आपके मामले के लिए एक गंदा और काम समाधान का प्रतिनिधित्व करता है।
एक न्यूनतम, काम उदाहरण (कि gtest उपयोग नहीं करता है, माफ करना, मैं मोबाइल एप्लिकेशन से कर रहा हूँ और इसे सीधे परीक्षण नहीं कर सकते):

#include<memory> 
#include<iostream> 
#include<utility> 

struct IBar { 
    virtual ~IBar() = default; 
    virtual void DoSth() = 0; 
}; 

struct Bar : public IBar { 
    void DoSth() override { std::cout <<"Bar is doing sth" << std::endl;};  
}; 

struct Foo { 
    Foo(std::unique_ptr<IBar> bar) : bar(std::move(bar)) {} 

    void DoIt() { 
     bar->DoSth(); 
    } 
private: 
    std::unique_ptr<IBar> bar; 
}; 

int main() { 
    std::unique_ptr<Bar> bar = std::make_unique<Bar>(); 
    std::shared_ptr<Bar> shared{std::shared_ptr<Bar>{}, bar.get()}; 
    Foo foo{std::move(bar)}; 
    shared->DoSth(); 
    foo.DoIt(); 
} 

मुझे लगता है कि अपने परीक्षण कुछ इस तरह बन जाएगा :

struct BarMock: public IBar { 
    MOCK_METHOD0(DoSth, void()); 
}; 

struct FooTest : public testing::Test { 
    FooTest() { 
     std::unique_ptr<BarMock> bar = std::make_unique<BarMock>(); 
     barMock = std::shared_ptr<BarMock>{std::shared_ptr<BarMock>{}, bar.get()}; 
     out = std::make_unique<Foo>{std::move(bar)}; 
    } 

    std::shared_ptr<BarMock> barMock; 
    std::unique_ptr<Foo> out; 
}; 

TEST_F(FooTest, shouldDoItWhenDoSth) { 
    EXPECT_CALL(*barMock, DoSth()); 
    out->DoIt(); 
} 

aliasing constructor क्या करता है?

template< class Y >  
shared_ptr( const shared_ptr<Y>& r, element_type *ptr ); 

निर्माता aliasing: constructs एक shared_ptr जो r साथ स्वामित्व जानकारी साझा करता है, लेकिन एक असंबंधित और अप्रबंधित सूचक ptr रखती है। भले ही यह shared_ptr गुंजाइश से बाहर निकलने के लिए समूह का आखिरी हिस्सा है, फिर भी यह मूल रूप से r द्वारा प्रबंधित ऑब्जेक्ट के लिए विनाशक को कॉल करेगा। हालांकि, इस पर get() पर कॉल करने से हमेशा ptr की एक प्रति वापस आ जाएगी। यह सुनिश्चित करने के लिए प्रोग्रामर की ज़िम्मेदारी यह है कि ptr तब तक मान्य रहेगा जब तक कि shared_ptr मौजूद है, जैसे कि ptrr द्वारा प्रबंधित ऑब्जेक्ट का सदस्य है या ऊर्फ (उदा।, r.get()

+1

साझा_ptr के एलियासिंग कन्स्ट्रक्टर के लिए +1, जानना अच्छा है। अगर मैं इसे सही ढंग से समझता हूं, तो अलियासिंग कन्स्ट्रक्टर के साथ बनाया गया shared_ptr पीटीआर पास नहीं कर रहा है, इसलिए यह नियमित कच्चे सूचक के रूप में काम करता है। या कच्चे पीआरटी के बजाय इसका उपयोग करने में कोई फायदा है? – Quarra

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