2008-10-31 13 views
6

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

अब मैं यूनिट परीक्षण के तहत कोड लाना चाहता हूं लेकिन हमारे द्वारा चुने गए ऑब्जेक्ट मॉडल पर विचार करने के लिए मुझे नहीं पता कि ऑब्जेक्ट्स का नकल कैसे करें।

नमूना हैडर (foo.h):

#ifndef FOO_H_ 
#define FOO_H_ 

typedef struct Foo_s* Foo; 
Foo foo_create(TcpSocket tcp_socket); 
void foo_destroy(Foo foo); 
int foo_transmit_command(Foo foo, enum Command command); 

#endif /* FOO_H_ */ 

नमूना स्रोत (foo.c): नीचे दिए गए उदाहरण देखें

struct Foo_s { 
    TcpSocket tcp_socket; 
}; 

Foo foo_create(TcpSocket tcp_socket) 
{ 
    Foo foo = NULL; 

    assert(tcp_socket != NULL); 

    foo = malloc(sizeof(struct Foo_s)); 
    if (foo == NULL) { 
     goto fail; 
    } 
    memset(foo, 0UL, sizeof(struct Foo_s)); 

    foo->tcp_socket = tcp_socket; 

    return foo; 

fail: 
    foo_destroy(foo); 
    return NULL; 
} 

void foo_destroy(Foo foo) 
{ 
    if (foo != NULL) { 
      tcp_socket_destroy(foo->tcp_socket); 
      memset(foo, 0UL, sizeof(struct Foo_s)); 
      free(foo); 
    } 
} 

int foo_transmit_command(Foo foo, enum Command command) 
{ 
    size_t len = 0; 
    struct FooCommandPacket foo_command_packet = {0}; 

    assert(foo != NULL); 
    assert((Command_MIN <= command) && (command <= Command_MAX)); 

    /* Serialize command into foo_command_packet struct */ 
    ... 

    len = tcp_socket_send(foo->tcp_socket, &foo_command_packet, sizeof(foo_command_packet)); 
    if (len < sizeof(foo_command_packet)) { 
      return -1; 
    } 
    return 0; 
} 

उदाहरण में ऊपर मैं नकली चाहते हैं TcpSocket ऑब्जेक्ट ताकि मैं इकाई परीक्षण के तहत "foo_transmit_command" ला सकता हूं लेकिन मुझे यकीन नहीं है कि विरासत के बिना इस बारे में कैसे जाना है। मैं वास्तव में vtables का उपयोग करने के लिए कोड को फिर से डिजाइन नहीं करना चाहता जब तक कि मुझे वास्तव में नहीं करना है। हो सकता है कि मजाक करने से इससे बेहतर दृष्टिकोण हो?

मेरा परीक्षण अनुभव मुख्य रूप से सी ++ से आता है और मुझे थोड़ा डर है कि मैंने खुद को यहां एक कोने में चित्रित किया होगा। मैं अधिक अनुभवी परीक्षकों की किसी भी सिफारिश की अत्यधिक सराहना करता हूं।

संपादित करें:
तरह रिचर्ड क्विर्क ने बताया यह वास्तव में "tcp_socket_send" करने के लिए कॉल कि मैं ओवरराइड करना चाहते है और मैं पुस्तकालय से असली tcp_socket_send प्रतीक को हटाने कब से परीक्षण को जोड़ने के बिना यह करने के लिए पसंद करेंगे इसे उसी बाइनरी में अन्य परीक्षणों द्वारा बुलाया जाता है।

.. मुझे लगता है कि करने के लिए है कि वहाँ इस समस्या का कोई स्पष्ट समाधान शुरू कर

उत्तर

3

आप tcp_socket_send_moc के लिए असली tcp_socket_send और डमी कार्यान्वयन के साथ tcp_socket_send_moc और लिंक करने के लिए tcp_socket_send फिर से परिभाषित करने मैक्रो का उपयोग कर सकते हैं।

#define tcp_socket_send tcp_socket_send_moc 
+0

मैं इसे शायद टीसीपी सॉकेट हेडर में डाल सकता हूं और इसे #ifdef परीक्षण में संलग्न कर सकता हूं .. #endif। अच्छा सुझाव। –

+0

आप अपने कोड को बेहतर तरीके से जानते हैं, मैं बस यह कहना चाहता था कि मैक्रो एक पूरी चीज है और गलत स्थान पर रखा गया मैक्रो समस्या का कारण बन सकता है जो – Ilya

0

सुनिश्चित नहीं हैं कि आप क्या हासिल करना चाहते हैं।

आप struct Foo_s करने के लिए सभी foo_ * समारोह सूचक सदस्यों के रूप में कार्य जोड़ सकते हैं लेकिन आप अभी भी स्पष्ट रूप से अपने वस्तु के लिए सूचक पारित करने के लिए के रूप में कोई अंतर्निहित this सी में की जरूरत है लेकिन यह आप कैप्सूलीकरण और बहुरूपता दे देंगे।

+0

मुझे यूनिट परीक्षणों में कोड प्राप्त करने के लिए कोड बेस "बस" के एक बड़े हिस्से को फिर से लिखना होगा, जिसे मैं अधिमानतः टालना चाहूंगा। –

0

आप किस ओएस का उपयोग कर रहे हैं? मैं तुम्हें जीएनयू/लिनक्स पर LD_PRELOAD साथ एक ओवरराइड कर सकता है विश्वास करते हैं: This slide looks useful.

+0

लिनक्स लेकिन कुछ मामलों में निर्भरताएं सभी एक ही लाइब्रेरी में रहते हैं, इसलिए यदि मैं दूसरी लाइब्रेरी को प्रीलोड करता हूं तो मैं उस ऑब्जेक्ट को ओवरराइड भी करूँगा जिसका मैं परीक्षण कर रहा हूं। –

+0

नहीं, लिंकर को केवल एक प्रतीक मिलेगा - tcp_socket_send - LD_PRELOAD में, अन्य सभी सामान्य रूप से जुड़े होंगे। –

2

TestDept पर एक नज़र डालें:
आप ध्यान से के लिए उचित स्थान का चयन करना होगा http://code.google.com/p/test-dept/

यह एक खुला स्रोत परियोजना है कि possiblity उपलब्ध कराने के उद्देश्य वैकल्पिक कार्यान्वयन के लिए, उदाहरण के लिए है स्टब्स, कार्यों का और रन-टाइम में बदलने में सक्षम होने के लिए जो कहा गया कार्य का कार्यान्वयन।

यह ऑब्जेक्ट फ़ाइलों को मैंगलिंग करके पूरा किया गया है जो परियोजना के होम पेज पर बहुत अच्छी तरह से वर्णित है।

+0

+1 को डीबग करना वास्तव में कठिन है - यह उच्च स्तर के एम्बेडेड कोड का परीक्षण करने का एक अच्छा विकल्प है, खासकर एप्लिकेशन स्पेस या इंफ्रास्ट्रक्चर स्पेस में। धन्यवाद! – tehnyit

0

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

1

वैकल्पिक रूप से, आप टेस्टएप TestApe Unit testing for embedded software का उपयोग कर सकते हैं - यह ऐसा कर सकता है, लेकिन ध्यान दें कि यह केवल सी है। यह इस तरह जाना होगा ->

int mock_foo_transmit_command(Foo foo, enum Command command) { 
    VALIDATE(foo, a); 
    VALIDATE(command, b); 
} 

void test(void) { 
    EXPECT_VALIDATE(foo_transmit_command, mock_foo_transmit_command); 
    foo_transmit_command(a, b); 
} 
0

इल्या के जवाब में जोड़ने के लिए। तुम यह केर सकते हो।

#define tcp_socket_send tcp_socket_send_moc 
#include "your_source_code.c" 

int tcp_socket_send_moc(...) 
{ ... } 

मैं जब इकाई परीक्षण बनाने स्रोत फ़ाइल में संशोधनों को कम करने के इकाई परीक्षण मॉड्यूल में स्रोत फ़ाइल को शामिल करने की तकनीक का उपयोग करें।

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

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